জাভা 8 সম্পত্তি দ্বারা পৃথক


454

জাভা 8-এ আমি কীভাবে Streamপ্রতিটি বস্তুর সম্পত্তির স্বতন্ত্রতা পরীক্ষা করে এপিআই ব্যবহার করে কোনও ফিল্টার ফিল্টার করতে পারি ?

উদাহরণস্বরূপ আমার কাছে Personঅবজেক্টের একটি তালিকা রয়েছে এবং আমি একই নামের লোকগুলিকে সরিয়ে দিতে চাই,

persons.stream().distinct();

কোনও Personঅবজেক্টের জন্য ডিফল্ট সমতা পরীক্ষা ব্যবহার করবে , সুতরাং আমার মতো কিছু দরকার,

persons.stream().distinct(p -> p.getName());

দুর্ভাগ্যক্রমে distinct()পদ্ধতিতে এ জাতীয় কোনও ওভারলোড নেই। Personশ্রেণীর অভ্যন্তরে সাম্যতা যাচাইয়ের সংশোধন না করে এটি কি সংক্ষিপ্তভাবে করা সম্ভব?

উত্তর:


554

distinctএকটি রাষ্ট্রীয় ফিল্টার হিসাবে বিবেচনা করুন । এখানে এমন একটি ফাংশন রয়েছে যা কোনও প্রাকটিকে ফেরত দেয় যা এটি আগে যা দেখেছে তার সম্পর্কে রাষ্ট্র বজায় রাখে এবং প্রদত্ত উপাদানটি প্রথমবার দেখা হয়েছিল কিনা তা ফিরে আসে:

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

তারপরে আপনি লিখতে পারেন:

persons.stream().filter(distinctByKey(Person::getName))

মনে রাখবেন যে যদি স্ট্রিমটি অর্ডার করা হয় এবং সমান্তরালে চালিত হয়, এটি অনুলিপিগুলির মধ্যে থেকে প্রথমটির পরিবর্তে স্বেচ্ছামূলক উপাদান সংরক্ষণ করবে distinct()

(এটি মূলত এই প্রশ্নের আমার উত্তর হিসাবে একই : স্বেচ্ছাসেবক কীতে জাভা লাম্বদা স্ট্রিম ডিস্ট্রিন্ট ()? )


27
আমি অনুমান করি আরও ভাল সামঞ্জস্যের জন্য যুক্তিটি হওয়া উচিত Function<? super T, ?>, এমন নয় Function<? super T, Object>। এছাড়াও এটি লক্ষ করা উচিত যে অর্ডার করা সমান্তরাল প্রবাহের জন্য এই দ্রবণটি কোন বস্তুটি বের করা হবে (সাধারণের বিপরীতে distinct()) গ্যারান্টি দেয় না । সিক্যুয়াল স্ট্রিমগুলির জন্য সিএইচএম ব্যবহার করার জন্য অতিরিক্ত ওভারহেড রয়েছে (যা @ নোসিড সলিউশনে অনুপস্থিত)। পরিশেষে এই সমাধানটি filterপদ্ধতির চুক্তিকে লঙ্ঘন করে যা জাভাডকের বর্ণিত হিসাবে পূর্বাভাস অবশ্যই রাজ্যহীন হতে হবে। তবুও upvated।
তাগীর ভালেভ

3
@ Java_newbie দ্বারা প্রত্যাবর্তিত পূর্বাভাসের উদাহরণটি distinctByKeyএটি সমান্তরাল প্রবাহের মধ্যে ব্যবহার হচ্ছে কিনা সে সম্পর্কে কোনও ধারণা নেই। এটি সমান্তরালভাবে ব্যবহৃত হচ্ছে এমন ক্ষেত্রে এটি সিএইচএম ব্যবহার করে, যদিও তাগির বলিভ উপরে উল্লিখিত হিসাবে ক্রমিক ক্ষেত্রে ওভারহেড যুক্ত করে।
স্টুয়ার্ট মার্ক

5
@ হোলান্ডাগো আপনি যদি ভবিষ্যদ্বাণী করা ইভেন্টটি সংরক্ষণ করে পুনরায় ব্যবহার করেন তবে এটি ব্যর্থ হবে distinctByKey। আপনি যদি distinctByKeyপ্রতিটি সময় কল করেন তবে এটি কাজ করে , যাতে এটি প্রতিবার একটি নতুন প্রেডিকেট ইভেন্ট তৈরি করে।
স্টুয়ার্ট

3
@ চিন্ময় না, এটা করা উচিত নয়। আপনি যদি ব্যবহার .filter(distinctByKey(...))। এটি একবারে পদ্ধতিটি কার্যকর করে এবং প্রাকটিকেটটি ফিরিয়ে দেবে। সুতরাং মূলত মানচিত্রটি ইতিমধ্যে পুনরায় ব্যবহার করা হচ্ছে যদি আপনি এটি একটি স্ট্রিমের মধ্যে সঠিকভাবে ব্যবহার করেন। আপনি যদি মানচিত্রটিকে স্থির করে তুলেন, মানচিত্রটি সমস্ত ব্যবহারের জন্য ভাগ করা হবে। সুতরাং আপনার যদি দুটি স্ট্রিম ব্যবহার করে থাকে তবে distinctByKey()দু'জনেই একই মানচিত্র ব্যবহার করবেন যা আপনি চান তা নয়।
g00glen00b

3
এটি সুও স্মার্ট এবং সম্পূর্ণ অ-সুস্পষ্ট। সাধারণত এটি একটি রাষ্ট্রীয় ল্যাম্বডা এবং অন্তর্নিহিত পদ্ধতিটির CallSiteসাথে যুক্ত হবে get$Lambda- যা Predicateসর্বকালের একটি নতুন উদাহরণ ফিরে আসবে , তবে সেই দৃষ্টান্তগুলি একইভাবে ভাগ হবে mapএবং functionযতদূর আমি বুঝতে পারি। খুব সুন্দর!
ইউজিন

150

বিকল্পটি হ'ল ব্যক্তিটিকে কী হিসাবে নামটি ব্যবহার করে মানচিত্রে রাখুন:

persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();

নোট করুন যে সদৃশ নামটির ক্ষেত্রে যে ব্যক্তিটি রাখা হয়েছে, সেটি প্রথম এনকন্টার হবে।


23
@ স্কিভি: আপনি কি মনে করেন distinct()যে ওভারহেড ছাড়া বাস্তবায়নের কোনও উপায় আছে ? এটি বাস্তবায়িত সমস্ত স্বতন্ত্র মূল্যবোধের কথা স্মরণ না করে যদি কোনও বস্তু আগে দেখে থাকে তবে কোনও বাস্তবায়ন কীভাবে জানবে? সুতরাং ওভারহেড toMapএবং distinctসম্ভবত সম্ভবত একই।
হলগার

1
@ ওভারহেড distinct()নিজেই তৈরি করবেন বলে আমি ভাবিনি যে আমি সেখানে ভুল হতে পারি ।
স্কিভি

2
এবং স্পষ্টতই এটি তালিকার মূল
ফিলিপ

10
@ ফিলিপ: এ পরিবর্তন করে স্থির করা যেতে পারেpersons.collect(toMap(Person::getName, p -> p, (p, q) -> p, LinkedHashMap::new)).values();
হোলার

1
@ ড্যানিয়েলআরওয়িকার এই প্রশ্নটি "সম্পত্তি অনুসারে পৃথক" সম্পর্কিত। স্ট্রিমটি একই সম্পত্তি দ্বারা বাছাই করা প্রয়োজন , এর সুবিধা নিতে সক্ষম হবে। প্রথমত, ওপি কখনই স্ট্রিমটি বাছাই করা হয় নি বলে জানিয়েছে। দ্বিতীয়ত, স্ট্রিমগুলি নির্দিষ্ট কোনও সম্পত্তি দ্বারা সাজানো হয়েছে কিনা তা সনাক্ত করতে সক্ষম হয় না । তৃতীয়ত, আপনার পরামর্শ অনুসারে কোনও প্রকৃত "সম্পত্তি দ্বারা পৃথক" স্ট্রিম অপারেশন নেই। চতুর্থ, অনুশীলনে, এই ধরণের সাজানো স্ট্রিম পাওয়ার জন্য কেবল দুটি উপায় রয়েছে ways একটি সাজানো উত্স ( TreeSet) যা ইতিমধ্যে যাইহোক বা sortedস্ট্রিমের মধ্যে স্বতন্ত্র যা এটি সমস্ত উপাদানকে বাফার করে।
30-30

101

আপনি কোনও ব্যক্তির নামের সাথে তুলনা করে সেই ব্যক্তিকে অন্য শ্রেণিতে আবদ্ধ করতে পারেন। এরপরে, আপনি কোনও ব্যক্তিকে আবার স্রোতে পেতে মোড়ানো বস্তুগুলি মোড়ক করুন। স্ট্রিম ক্রিয়াকলাপগুলি নীচের হিসাবে দেখতে পারে:

persons.stream()
    .map(Wrapper::new)
    .distinct()
    .map(Wrapper::unwrap)
    ...;

ক্লাসটি নীচের মত দেখতে Wrapperপারে:

class Wrapper {
    private final Person person;
    public Wrapper(Person person) {
        this.person = person;
    }
    public Person unwrap() {
        return person;
    }
    public boolean equals(Object other) {
        if (other instanceof Wrapper) {
            return ((Wrapper) other).person.getName().equals(person.getName());
        } else {
            return false;
        }
    }
    public int hashCode() {
        return person.getName().hashCode();
    }
}


5
@ স্টুয়ার্টকায়ে আসলেই নয় ... কোনও স্মৃতিচারণ নেই, এবং বিন্দুটি পারফরম্যান্স নয়, তবে বিদ্যমান এপিআইতে অভিযোজন।
মার্কো টপলনিক

6
com.google.common.base.Equivalence.wrap (S) এবং com.google.common.base.Equivalence.Wrapper.get () খুব সাহায্য করতে পারে।
বিজিএম

আপনি একটি কী নিষ্কাশন ফাংশন দ্বারা মোড়ক ক্লাসটিকে জেনেরিক এবং প্যারামিট্রাইজ করতে পারেন।
লি

equalsপদ্ধতি সরলীকৃত করা যেতে পারেreturn other instanceof Wrapper && ((Wrapper) other).person.getName().equals(person.getName());
হোলগার

55

আর একটি সমাধান, ব্যবহার করে Set। আদর্শ সমাধান নাও হতে পারে তবে এটি কাজ করে

Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());

অথবা আপনি যদি মূল তালিকাটি সংশোধন করতে পারেন তবে আপনি অপসারণ পদ্ধতিটি ব্যবহার করতে পারেন

persons.removeIf(p -> !set.add(p.getName()));

2
আপনি যদি কোনও তৃতীয় পক্ষের লাইব্রেরি ব্যবহার না করে থাকেন তবে এটি সেরা উত্তর!
মনোজ শ্রেষ্ঠ

5
জেনিয়েন্ট ধারণাটি ব্যবহার করে যে সেট.এডডি সত্যটি প্রত্যাশা করে যদি এই সেটটিতে ইতিমধ্যে নির্দিষ্ট উপাদান অন্তর্ভুক্ত না থাকে। +1
লুভি

আমি বিশ্বাস করি যে এই পদ্ধতিটি সমান্তরাল স্ট্রিম প্রসেসিংয়ের জন্য কাজ করে না, কারণ এটি থ্রেড-নিরাপদ নয়।
লোবো

@ লোবো সম্ভবত না। এটি কেবল একটি ধারণা, যা সাধারণ ক্ষেত্রে কাজ করবে। ব্যবহারকারীরা থ্রেড সুরক্ষা / সমান্তরালতার জন্য এটি প্রসারিত করতে পারে।
সান্থোষ ২

আকর্ষণীয় দৃষ্টিভঙ্গি, তবে অন্য সংগ্রহের (ব্যক্তি) স্ট্রিম ফিল্টার করার সময় একটি বাহ্যিক সংগ্রহ (সেট) সংশোধন করার জন্য এন্টি-প্যাটার্নের মতো দেখায় ...
জাস্টিন রোউ

31

একটি কাস্টম তুলকের সাথে একটি ট্রিসেট ব্যবহার করে একটি সহজ পদ্ধতি রয়েছে।

persons.stream()
    .collect(Collectors.toCollection(
      () -> new TreeSet<Person>((p1, p2) -> p1.getName().compareTo(p2.getName())) 
));

4
আমি মনে করি আপনার উত্তরটি অর্ডারিংয়ের দিকে সহায়তা করে না স্বতন্ত্রতার দিকে। তবে এটি আমাকে কীভাবে এটি করতে পারে সে সম্পর্কে আমার চিন্তাভাবনা স্থির করতে সহায়তা করে। : এখানে চেক করুন stackoverflow.com/questions/1019854/...
janagn

মনে রাখবেন আপনি এখানে উপাদানগুলিকে বাছাইয়ের জন্য মূল্য প্রদান করবেন এবং নকলগুলি খুঁজে পেতে বা এমনকি নকলগুলি সরাতে আমাদের বাছাই করার প্রয়োজন নেই।
পিসারুক

12
তুলনামূলক ডট কম (পার্সন :: getName)
জিন-

24

আমরা আরএক্সজাভাও ব্যবহার করতে পারি (খুব শক্তিশালী প্রতিক্রিয়াশীল এক্সটেনশন লাইব্রেরি)

Observable.from(persons).distinct(Person::getName)

অথবা

Observable.from(persons).distinct(p -> p.getName())

আরএক্স দুর্দান্ত, তবে এটি একটি খারাপ উত্তর। Observableএটি পুশ-ভিত্তিক যেখানে Streamপুল-ভিত্তিক। stackoverflow.com/questions/30216979/...
sdgfsdh

4
প্রশ্নটি প্রয়োজনীয়ভাবে স্ট্রিমটি ব্যবহার না করে একটি জাভা 8 সমাধান চাইবে। আমার উত্তরটি দেখায় যে জাভা 8 স্ট্রিম এপিআই আরএক্স এপিআই এর চেয়ে কম পাউফুল
ফ্রি্যাক করুন

1
চুল্লি ব্যবহার করে , এটি হবেFlux.fromIterable(persons).distinct(p -> p.getName())
রীতেশ

প্রশ্নটি আক্ষরিকভাবে " Streamএপিআই ব্যবহার করে " বলে, "প্রয়োজনীয় স্ট্রিম ব্যবহার করা দরকার নয়" says এটি বলেছিল, এটি পৃথক মানগুলিতে স্ট্রিম ফিল্টার করার এক্সওয়াই সমস্যার একটি দুর্দান্ত সমাধান।
এম জাস্টিন 16

12

আপনি groupingByসংগ্রাহক ব্যবহার করতে পারেন :

persons.collect(Collectors.groupingBy(p -> p.getName())).values().forEach(t -> System.out.println(t.get(0).getId()));

আপনি যদি অন্য স্ট্রিম পেতে চান তবে আপনি এটি ব্যবহার করতে পারেন:

persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream().map(l -> (l.get(0)));

11

আপনি Eclipse সংগ্রহেdistinct(HashingStrategy) পদ্ধতিটি ব্যবহার করতে পারেন ।

List<Person> persons = ...;
MutableList<Person> distinct =
    ListIterate.distinct(persons, HashingStrategies.fromFunction(Person::getName));

আপনি যদি personsএক্লিপ্স কালেকশন ইন্টারফেসটি প্রয়োগ করতে রিফ্যাক্টর করতে পারেন তবে আপনি সরাসরি তালিকায় পদ্ধতিটি কল করতে পারেন।

MutableList<Person> persons = ...;
MutableList<Person> distinct =
    persons.distinct(HashingStrategies.fromFunction(Person::getName));

হ্যাশিংস্ট্রেজি কেবল একটি কৌশল ইন্টারফেস যা আপনাকে সমান এবং হ্যাশকোডের কাস্টম বাস্তবায়ন সংজ্ঞায়িত করতে দেয়।

public interface HashingStrategy<E>
{
    int computeHashCode(E object);
    boolean equals(E object1, E object2);
}

দ্রষ্টব্য: আমি গ্রহগ্রাহ সংগ্রহের প্রতিশ্রুতিবদ্ধ।


পদ্ধতিটি স্পষ্টবাইয়ের সাথে এক্সিলিপস সংগ্রহ 9.0 এ যুক্ত করা হয়েছিল যা এই সমাধানটিকে আরও সহজ করতে পারে। मध्यम.com
ডোনাল্ড রাব

10

আমি Vavr ব্যবহার করার পরামর্শ দিচ্ছি , আপনি যদি পারেন। এই লাইব্রেরির সাহায্যে আপনি নিম্নলিখিতগুলি করতে পারেন:

io.vavr.collection.List.ofAll(persons)
                       .distinctBy(Person::getName)
                       .toJavaSet() // or any another Java 8 Collection

পূর্বে "জাভাসলং" গ্রন্থাগার হিসাবে পরিচিত।
ব্যবহারকারী 11153

9

আপনি স্ট্রিমএক্স লাইব্রেরি ব্যবহার করতে পারেন :

StreamEx.of(persons)
        .distinct(Person::getName)
        .toList()

দুর্ভাগ্যক্রমে, অন্যথায় দুর্দান্ত স্ট্রিমএক্স লাইব্রেরির সেই পদ্ধতিটি খারাপভাবে ডিজাইন করা হয়েছে - এটি সমান ব্যবহারের পরিবর্তে অবজেক্টের সাম্যের তুলনা করে। এটি Stringস্ট্রিং ইন্টার্নিংয়ের জন্য ধন্যবাদগুলির জন্য কাজ করতে পারে , তবে এটি নাও পারে।
টর্ক

7

স্টুয়ার্ট মার্কসের উত্তর প্রসারিত করা, এটি একটি সংক্ষিপ্ত উপায়ে এবং সমবর্তী মানচিত্র ছাড়াই করা যেতে পারে (যদি আপনার সমান্তরাল প্রবাহের প্রয়োজন না হয়):

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    final Set<Object> seen = new HashSet<>();
    return t -> seen.add(keyExtractor.apply(t));
}

তারপরে কল করুন:

persons.stream().filter(distinctByKey(p -> p.getName());

2
এইটি বিবেচনায় নেই যে প্রবাহটি সমান্তরাল হতে পারে।
brunnsbe

মন্তব্যের জন্য ধন্যবাদ, আমি আমার উত্তর আপডেট করেছি। আপনার যদি সমান্তরাল স্ট্রিমের প্রয়োজন না হয়, সমবর্তী মানচিত্র ব্যবহার না করা আপনাকে আরও ভাল পারফরম্যান্স দেয়।
ওয়াজেসিচ গারস্কি

আপনি যদি এর Collections.synchronizedSet(new HashSet<>())পরিবর্তে কোনও কোড তৈরি করেন তবে আপনার কোড সম্ভবত সমান্তরাল সংগ্রহের জন্য কাজ করবে । তবে এটি সম্ভবত একটি এর চেয়ে ধীর হবে ConcurrentHashMap
লিই

7

অনুরূপ পন্থা যা সাইদ জারিনফাম ব্যবহার করেছেন তবে আরও জাভা 8 স্টাইল :)

persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream()
 .map(plans -> plans.stream().findFirst().get())
 .collect(toList());

1
আমি মানচিত্রের লাইনটি প্রতিস্থাপন করব flatMap(plans -> plans.stream().findFirst().stream())এটির সাথে get
চ্ছিক

FlatMap (পরিকল্পনা -> plans.stream () সীমা (1)।): হয়তো এটাও ঠিক আছে
Rrr

6

আমি একটি জেনেরিক সংস্করণ তৈরি করেছি:

private <T, R> Collector<T, ?, Stream<T>> distinctByKey(Function<T, R> keyExtractor) {
    return Collectors.collectingAndThen(
            toMap(
                    keyExtractor,
                    t -> t,
                    (t1, t2) -> t1
            ),
            (Map<R, T> map) -> map.values().stream()
    );
}

একটি উদাহরণ:

Stream.of(new Person("Jean"), 
          new Person("Jean"),
          new Person("Paul")
)
    .filter(...)
    .collect(distinctByKey(Person::getName)) // return a stream of Person with 2 elements, jean and Paul
    .map(...)
    .collect(toList())



5

আমার এই বিষয়ে আমার দৃষ্টিভঙ্গি হ'ল একই সম্পত্তি সহ সমস্ত বস্তুকে এক সাথে গোষ্ঠীভুক্ত করা, তারপরে গ্রুপগুলি 1 টি আকারে কেটে নিন এবং শেষ পর্যন্ত এগুলি হিসাবে সংগ্রহ করুন List

  List<YourPersonClass> listWithDistinctPersons =   persons.stream()
            //operators to remove duplicates based on person name
            .collect(Collectors.groupingBy(p -> p.getName()))
            .values()
            .stream()
            //cut short the groups to size of 1
            .flatMap(group -> group.stream().limit(1))
            //collect distinct users as list
            .collect(Collectors.toList());

3

স্বতন্ত্র বস্তুর তালিকাটি ব্যবহার করে পাওয়া যাবে:

 List distinctPersons = persons.stream()
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person:: getName))),
                            ArrayList::new));

2

এটি কার্যকর করার সহজতম উপায় হ'ল সাজ্ট বৈশিষ্ট্যটিতে ঝাঁপ দেওয়া কারণ এটি ইতিমধ্যে একটি anচ্ছিক সরবরাহ করে Comparatorযা কোনও উপাদানের সম্পত্তি ব্যবহার করে তৈরি করা যেতে পারে। তারপরে আপনাকে ডুপ্লিকেটগুলি ফিল্টার করতে হবে Predicateযা স্টেটফুল ব্যবহার করে করা যেতে পারে যা একটি সাজানো স্ট্রিমের জন্য সমস্ত সমান উপাদান সংলগ্ন এই সত্যটি ব্যবহার করে:

Comparator<Person> c=Comparator.comparing(Person::getName);
stream.sorted(c).filter(new Predicate<Person>() {
    Person previous;
    public boolean test(Person p) {
      if(previous!=null && c.compare(previous, p)==0)
        return false;
      previous=p;
      return true;
    }
})./* more stream operations here */;

অবশ্যই, একটি স্টেটফুল Predicateথ্রেড-নিরাপদ নয়, তবে এটি যদি আপনার প্রয়োজন হয় তবে আপনি এই যুক্তিটিকে একটিতে স্থানান্তর করতে পারেন Collectorএবং আপনার ব্যবহার করার সময় স্ট্রিমটি থ্রেড-সুরক্ষার যত্ন নিতে পারেন Collector। এটি আপনার স্বতন্ত্র উপাদানগুলির প্রবাহের সাথে আপনি কী করতে চান তার উপর নির্ভর করে যা আপনি আপনার প্রশ্নে আমাদের জানাননি।


1

@ জোসকেট্রেসের উত্তরে বিল্ডিং করে আমি একটি জেনেরিক ইউটিলিটি পদ্ধতি তৈরি করেছি:

আপনি একজন কালেক্টর তৈরি করে এই আরও জাভা 8-বান্ধব করে তুলতে পারেন ।

public static <T> Set<T> removeDuplicates(Collection<T> input, Comparator<T> comparer) {
    return input.stream()
            .collect(toCollection(() -> new TreeSet<>(comparer)));
}


@Test
public void removeDuplicatesWithDuplicates() {
    ArrayList<C> input = new ArrayList<>();
    Collections.addAll(input, new C(7), new C(42), new C(42));
    Collection<C> result = removeDuplicates(input, (c1, c2) -> Integer.compare(c1.value, c2.value));
    assertEquals(2, result.size());
    assertTrue(result.stream().anyMatch(c -> c.value == 7));
    assertTrue(result.stream().anyMatch(c -> c.value == 42));
}

@Test
public void removeDuplicatesWithoutDuplicates() {
    ArrayList<C> input = new ArrayList<>();
    Collections.addAll(input, new C(1), new C(2), new C(3));
    Collection<C> result = removeDuplicates(input, (t1, t2) -> Integer.compare(t1.value, t2.value));
    assertEquals(3, result.size());
    assertTrue(result.stream().anyMatch(c -> c.value == 1));
    assertTrue(result.stream().anyMatch(c -> c.value == 2));
    assertTrue(result.stream().anyMatch(c -> c.value == 3));
}

private class C {
    public final int value;

    private C(int value) {
        this.value = value;
    }
}

1

কারও পক্ষে উপকারী হতে পারে। আমার আরেকটু প্রয়োজন ছিল। Aতৃতীয় পক্ষের থেকে অবজেক্টের তালিকা থাকার সাথে একই A.bক্ষেত্র রয়েছে এমন সমস্তগুলি সরিয়ে ফেলুন A.id( তালিকায় Aএকই সাথে একাধিক অবজেক্ট A.id)। স্ট্রিম পার্টিশনের উত্তর তাগীর বলিভ দ্বারা আমাকে কাস্টম ব্যবহার করতে অনুপ্রাণিত করেছিল Collectorযা প্রত্যাবর্তন করে Map<A.id, List<A>>। সরল flatMapবাকি কাজ করবে।

 public static <T, K, K2> Collector<T, ?, Map<K, List<T>>> groupingDistinctBy(Function<T, K> keyFunction, Function<T, K2> distinctFunction) {
    return groupingBy(keyFunction, Collector.of((Supplier<Map<K2, T>>) HashMap::new,
            (map, error) -> map.putIfAbsent(distinctFunction.apply(error), error),
            (left, right) -> {
                left.putAll(right);
                return left;
            }, map -> new ArrayList<>(map.values()),
            Collector.Characteristics.UNORDERED)); }

1

আমার একটি পরিস্থিতি ছিল, যেখানে আমি 2 কীগুলির উপর ভিত্তি করে তালিকা থেকে স্বতন্ত্র উপাদানগুলি পেয়েছিলাম বলে মনে করি। আপনি যদি দুটি কী এর উপর ভিত্তি করে স্বতন্ত্র চান বা সমন্বিত কী ব্যবহার করতে পারেন তবে এটি চেষ্টা করে দেখুন

class Person{
    int rollno;
    String name;
}
List<Person> personList;


Function<Person, List<Object>> compositeKey = personList->
        Arrays.<Object>asList(personList.getName(), personList.getRollno());

Map<Object, List<Person>> map = personList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));

List<Object> duplicateEntrys = map.entrySet().stream()`enter code here`
        .filter(settingMap ->
                settingMap.getValue().size() > 1)
        .collect(Collectors.toList());

0

আমার ক্ষেত্রে আমার পূর্ববর্তী উপাদানটি কী ছিল তা নিয়ন্ত্রণ করা দরকার। এরপরে আমি একটি রাষ্ট্রীয় পূর্বানুমতি তৈরি করেছিলাম যেখানে পূর্ববর্তী উপাদানটি বর্তমান উপাদান থেকে আলাদা থাকলে আমি চুক্তি করেছিলাম, সে ক্ষেত্রে আমি এটি রেখে দিয়েছিলাম।

public List<Log> fetchLogById(Long id) {
    return this.findLogById(id).stream()
        .filter(new LogPredicate())
        .collect(Collectors.toList());
}

public class LogPredicate implements Predicate<Log> {

    private Log previous;

    public boolean test(Log atual) {
        boolean isDifferent = previouws == null || verifyIfDifferentLog(current, previous);

        if (isDifferent) {
            previous = current;
        }
        return isDifferent;
    }

    private boolean verifyIfDifferentLog(Log current, Log previous) {
        return !current.getId().equals(previous.getId());
    }

}

0

এই তালিকাতে আমার সমাধান:

List<HolderEntry> result ....

List<HolderEntry> dto3s = new ArrayList<>(result.stream().collect(toMap(
            HolderEntry::getId,
            holder -> holder,  //or Function.identity() if you want
            (holder1, holder2) -> holder1 
    )).values());

আমার পরিস্থিতিতে আমি স্বতন্ত্র মানগুলি খুঁজে পেতে এবং তাদের তালিকায় রাখতে চাই।


0

যদিও সর্বোচ্চ আপোভোট করা উত্তর একেবারে সেরা উত্তর জাভা 8, এটি একই সময়ে পারফরম্যান্সের দিক থেকে একেবারে খারাপ। আপনি যদি সত্যিই খারাপ লো পারফরম্যান্ট অ্যাপ্লিকেশন চান, তবে এগিয়ে যান এবং এটি ব্যবহার করুন। ব্যক্তির নামগুলির একটি অনন্য সেট আহরণের সহজ প্রয়োজনীয়তা কেবলমাত্র "প্রতিটি-জন্য" এবং একটি "সেট" দ্বারা অর্জন করা হবে। তালিকা 10 এর আকারের উপরে থাকলে জিনিসগুলি আরও খারাপ হয়।

আপনার 20 টি অবজেক্টের সংগ্রহ রয়েছে তা বিবেচনা করুন:

public static final List<SimpleEvent> testList = Arrays.asList(
            new SimpleEvent("Tom"), new SimpleEvent("Dick"),new SimpleEvent("Harry"),new SimpleEvent("Tom"),
            new SimpleEvent("Dick"),new SimpleEvent("Huckle"),new SimpleEvent("Berry"),new SimpleEvent("Tom"),
            new SimpleEvent("Dick"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("Cherry"),
            new SimpleEvent("Roses"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("gotya"),
            new SimpleEvent("Gotye"),new SimpleEvent("Nibble"),new SimpleEvent("Berry"),new SimpleEvent("Jibble"));

আপনি আপত্তি যেখানে SimpleEventএই মত দেখাচ্ছে:

public class SimpleEvent {

private String name;
private String type;

public SimpleEvent(String name) {
    this.name = name;
    this.type = "type_"+name;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}
}

এবং পরীক্ষা করার জন্য আপনার কাছে জেএমএইচ কোড রয়েছে, (দয়া করে নোট করুন, আমি স্বীকৃত উত্তরে উল্লিখিত একই স্বতন্ত্রবাইকি প্রিডিকেট ব্যবহার করছি ):

@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public void aStreamBasedUniqueSet(Blackhole blackhole) throws Exception{

    Set<String> uniqueNames = testList
            .stream()
            .filter(distinctByKey(SimpleEvent::getName))
            .map(SimpleEvent::getName)
            .collect(Collectors.toSet());
    blackhole.consume(uniqueNames);
}

@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public void aForEachBasedUniqueSet(Blackhole blackhole) throws Exception{
    Set<String> uniqueNames = new HashSet<>();

    for (SimpleEvent event : testList) {
        uniqueNames.add(event.getName());
    }
    blackhole.consume(uniqueNames);
}

public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(MyBenchmark.class.getSimpleName())
            .forks(1)
            .mode(Mode.Throughput)
            .warmupBatchSize(3)
            .warmupIterations(3)
            .measurementIterations(3)
            .build();

    new Runner(opt).run();
}

তারপরে আপনার বেঞ্চমার্কের ফলাফলগুলি এরকম হবে:

Benchmark                                  Mode  Samples        Score  Score error  Units
c.s.MyBenchmark.aForEachBasedUniqueSet    thrpt        3  2635199.952  1663320.718  ops/s
c.s.MyBenchmark.aStreamBasedUniqueSet     thrpt        3   729134.695   895825.697  ops/s

এবং আপনি দেখতে পাচ্ছেন, জাভা 8 স্ট্রিমের তুলনায় একটি সরল ফর-ফ্রি হ'ল থ্রুপুটটিতে 3 গুণ ভাল এবং ত্রুটি স্কোরের চেয়ে কম।

উচ্চ থ্রুপুট, ভাল পারফরম্যান্স


1
ধন্যবাদ, তবে প্রশ্নটি খুব সুনির্দিষ্টভাবে স্ট্রিম এপিআইয়ের প্রসঙ্গে ছিল
রিচকে

হ্যাঁ, আমি সম্মত, আমি ইতিমধ্যে উল্লেখ করেছি "যদিও সর্বোচ্চ আপোভোটেড উত্তরটি একেবারে সেরা উত্তর জাভা 8"। সমস্যাটি বিভিন্নভাবে সমাধান করা যেতে পারে এবং আমি এখানে হাইলাইট করার চেষ্টা করছি যে জাভা 8 স্ট্রিমগুলির সাথে বিপজ্জনকভাবে না হয়ে বরং সমস্যাটি সহজভাবে সমাধান করা যেতে পারে, যেখানে বিপদটি কার্য সম্পাদনের অবনতি। :)
অভিনব গাঙ্গুলি

-2

আপনি নিম্নলিখিত ব্যক্তির তালিকা করতে চান তবে সহজ উপায় হবে

Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());

উপরন্তু, যদি আপনি স্বতন্ত্র অথবা অনন্য খুঁজতে চান নামের তালিকা , ব্যক্তি , আপনি পাশাপাশি দুই পদ্ধতি নিম্নলিখিত ব্যবহার করতে পারেন।

পদ্ধতি 1: ব্যবহার distinct

persons.stream().map(x->x.getName()).distinct.collect(Collectors.toList());

পদ্ধতি 2: ব্যবহার HashSet

Set<E> set = new HashSet<>();
set.addAll(person.stream().map(x->x.getName()).collect(Collectors.toList()));

2
এটি নাম নয়, একটি তালিকা তৈরি করে Person
হাল্ক

1
আমি ঠিক এটিই খুঁজছিলাম। সংগ্রহটিকে অন্যকে রূপান্তর করার সময় সদৃশগুলি মুছে ফেলার জন্য আমার একক লাইন পদ্ধতি দরকার। ধন্যবাদ।
রাজ

-3

আপনি লিখতে পারেন সবচেয়ে সহজ কোড:

    persons.stream().map(x-> x.getName()).distinct().collect(Collectors.toList());

12
এটি নামের একটি স্বতন্ত্র তালিকা পাবে, নাম অনুসারে ব্যক্তি নয়
রিচক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.