জাভা 8 এ একাধিক ক্ষেত্রের নাম অনুসারে গ্রুপ করুন


90

আমি POJO- র কোনও ক্ষেত্রের নাম দ্বারা অবজেক্টগুলিকে গোষ্ঠীকরণের জন্য কোডটি পেয়েছি। নীচে এর জন্য কোড দেওয়া হল:

public class Temp {

    static class Person {

        private String name;
        private int age;
        private long salary;

        Person(String name, int age, long salary) {

            this.name = name;
            this.age = age;
            this.salary = salary;
        }

        @Override
        public String toString() {
            return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);
        }
    }

    public static void main(String[] args) {
        Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
                new Person("Mark", 30, 30000),
                new Person("Will", 28, 28000),
                new Person("William", 28, 28000));
        Map<Integer, List<Person>> peopleByAge;
        peopleByAge = people
                .collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
        System.out.println(peopleByAge);
    }
}

এবং আউটপুটটি (যা সঠিক):

{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}

তবে আমি যদি একাধিক ক্ষেত্রের দ্বারা গ্রুপ করতে চাই তবে কী হবে? আমি অবশ্যই সেই পজো পদ্ধতি groupingBy()প্রয়োগের পরে পদ্ধতিতে কিছু পজো পাস করতে পারি equals()তবে প্রদত্ত পিওজিও থেকে আমি একাধিক ক্ষেত্র দ্বারা গ্রুপ করতে পারি এর মতো অন্য কোনও বিকল্প নেই কি?

যেমন এখানে আমার ক্ষেত্রে, আমি নাম এবং বয়স অনুসারে গ্রুপ করতে চাই।


4
একটি কৌশলটি হ'ল সমস্ত ক্ষেত্র থেকে একটি অনন্য স্ট্রিং তৈরি করা।
মার্কো টপলনিক

4
mappingডাউনস্ট্রিম সংগ্রাহক হিসাবে বিটিডাব্লু আপনার পোস্ট করা কোডটিতে রিডান্ট্যান্ট ।
মার্কো টপলনিক

8
দ্রুত এবং নোংরা সমাধান হয় people.collect(groupingBy(p -> Arrays.asList(p.name, p.age)))
মিশা

উত্তর:


163

আপনার এখানে কয়েকটি বিকল্প রয়েছে। আপনার সংগ্রাহকদের চেইন করা সবচেয়ে সহজ:

Map<String, Map<Integer, List<Person>>> map = people
    .collect(Collectors.groupingBy(Person::getName,
        Collectors.groupingBy(Person::getAge));

তারপরে ফ্রেড নামে পরিচিত 18 বছরের পুরানো লোকের একটি তালিকা পেতে আপনি ব্যবহার করবেন:

map.get("Fred").get(18);

একটি দ্বিতীয় বিকল্পটি এমন একটি শ্রেণীর সংজ্ঞা দেওয়া যা গোষ্ঠীভুক্ত করে। এটি ব্যক্তির ভিতরে থাকতে পারে। এই কোডটি একটি ব্যবহার করে recordতবে এটি JEP 359 যুক্ত হওয়ার আগে জাভা সংস্করণে ঠিক তত সহজেই একটি শ্রেণি হতে পারে ( সংজ্ঞায়িত equalsএবং hashCodeসংজ্ঞায়িত) হতে পারে :

class Person {
    record NameAge(String name, int age) { }

    public NameAge getNameAge() {
        return new NameAge(name, age);
    }
}

তারপরে আপনি ব্যবহার করতে পারেন:

Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));

এবং অনুসন্ধান করুন

map.get(new NameAge("Fred", 18));

অবশেষে যদি আপনি নিজের গ্রুপ রেকর্ডটি প্রয়োগ করতে না চান তবে আশেপাশের অনেক জাভা ফ্রেমওয়ার্কের pairকাছে এই ধরণের জিনিসটির জন্য নকশাকৃত একটি ক্লাস রয়েছে। উদাহরণস্বরূপ: অ্যাপাচি কমন্স জোড় আপনি যদি এই লাইব্রেরিগুলির মধ্যে একটি ব্যবহার করেন তবে আপনি মানচিত্রের চাবিটি নাম এবং বয়সের একটি জুড়ি তৈরি করতে পারেন:

Map<Pair<String, Integer>, List<Person>> map =
    people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));

এবং এর সাথে পুনরুদ্ধার:

map.get(Pair.of("Fred", 18));

ব্যক্তিগতভাবে আমি জেনেরিক টিপলগুলিতে এখন সত্যিই খুব বেশি মূল্য দেখতে পাচ্ছি না যে রেকর্ডগুলি ভাষায় উপলভ্য হিসাবে রেকর্ডগুলি আরও ভাল সংজ্ঞা প্রদর্শন করে এবং খুব কম কোডের প্রয়োজন হয়।


4
Function<T,U>এছাড়াও এই অর্থে অভিপ্রায় লুকিয়ে রাখে --- তবে আপনি প্রতিটি ম্যাপিং পদক্ষেপের জন্য তাদের নিজস্ব কার্যকরী ইন্টারফেস ঘোষণা করতে দেখবেন না; অভিপ্রায়টি ইতিমধ্যে ল্যাম্বডা দেহে রয়েছে। টিপলসের সাথে একই: তারা এপিআই উপাদানগুলির মধ্যে আঠালো প্রকার হিসাবে দুর্দান্ত। বিটিডাব্লু স্কালার কেস ক্লাসগুলি সংক্ষিপ্ততা এবং অভিপ্রায় উভয় ক্ষেত্রেই বড় জয় আইএমএইচও।
মার্কো তোপোলনিক

4
হ্যাঁ আমি আপনার বক্তব্য দেখতে পাচ্ছি। আমার ধারণা (সর্বদা মত) এটি কীভাবে ব্যবহৃত হয় তা নির্ভর করে। আমি উপরে যে উদাহরণটি দিয়েছি - একটি জোড়ার সাথে মানচিত্রের কী হিসাবে ব্যবহার করা - এটি কীভাবে না করা যায় তার একটি উত্তম উদাহরণ। আমি স্কালার সাথে খুব বেশি পরিচিত নই - ভাল জিনিস শুনলেই এটি শিখতে হবে start
স্প্রিন্টার

4
শুধু ঘোষণা করতে পারবেন ভাবুন NameAgeএক মাছ ধরার নৌকা হিসাবে: case class NameAge { val name: String; val age: Int }--- এবং আপনি পেতে equals, hashCodeএবং toString!
মার্কো তোপোলনিক

4
ভাল - আমার আইটেম 'করণীয়' কিউয়ের উপরে চাপানো অন্য আইটেম। দুর্ভাগ্যক্রমে এটি ফিফো!
ছড়িয়ে ছিটিয়ে

@ স্প্রিন্টার প্রথম কোড স্নিপেটের ধরণটি সঠিক নয় এবং এটি পরিবর্তন করতে হবেMap<String, Map<Integer, List<Person>>> map
কাসুর

38

এখানে কোডটি দেখুন:

আপনি কেবল একটি ফাংশন তৈরি করতে পারেন এবং এটি আপনার জন্য কাজ করতে দেয়, একধরণের ক্রিয়ামূলক স্টাইল!

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

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

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

চিয়ার্স!


4
আমি এই সমাধানটি ব্যবহার করেছি তবে ভিন্ন। ফাংশন <ব্যক্তি, স্ট্রিং> compositeKey = personRecord -> StringUtils.join (personRecord.getName (), personRecord.getAge ());
বিপিড্রোসো

8

groupingByপদ্ধতি প্রথম প্যারামিটার হয়েছে Function<T,K>যেখানে:

@ <T>ইনপুট উপাদানগুলির প্রকারটি পূর্ণ করুন

@ <K>কী কী ধরণের তা প্রমান করুন

আমরা যদি আপনার কোডের বেনাম শ্রেণীর সাথে ল্যাম্বদা প্রতিস্থাপন করি তবে আমরা এরকম কিছু দেখতে পাচ্ছি:

people.stream().collect(Collectors.groupingBy(new Function<Person, int>() {
            @Override
            public int apply(Person person) {
                return person.getAge();
            }
        }));

এখনই আউটপুট প্যারামিটার পরিবর্তন করুন <K>। এই ক্ষেত্রে, উদাহরণস্বরূপ, আমি নাম এবং বয়স অনুসারে গ্রুপিংয়ের জন্য org.apache.commons.lang3.tuple থেকে একটি জোড় শ্রেণি ব্যবহার করেছি, তবে আপনার প্রয়োজন অনুযায়ী ফিল্টারিং গ্রুপগুলির জন্য আপনি নিজের ক্লাস তৈরি করতে পারেন।

people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() {
                @Override
                public YourFilter apply(Person person) {
                    return Pair.of(person.getAge(), person.getName());
                }
            }));

অবশেষে, ল্যাম্বদা পিছনে প্রতিস্থাপনের পরে কোডটি এর মতো দেখাচ্ছে:

Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));

ব্যবহার সম্পর্কে কি List<String>?
অ্যালেক্স 78191

6

হাই আপনি কেবল নিজের groupingByKeyমত করে কনটেটেট করতে পারেন

Map<String, List<Person>> peopleBySomeKey = people
                .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



//write getGroupingByKey() function
private String getGroupingByKey(Person p){
return p.getAge()+"-"+p.getName();
}

2

আপনার গ্রুপে কী সংজ্ঞা দেওয়ার জন্য একটি শ্রেণী নির্ধারণ করুন।

class KeyObj {

    ArrayList<Object> keys;

    public KeyObj( Object... objs ) {
        keys = new ArrayList<Object>();

        for (int i = 0; i < objs.length; i++) {
            keys.add( objs[i] );
        }
    }

    // Add appropriate isEqual() ... you IDE should generate this

}

এখন আপনার কোডে,

peopleByManyParams = people
            .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));

4
এটি কেবল পুনর্নবীকরণ Ararys.asList()--- যা বিটিডাব্লু হ'ল ওপির ক্ষেত্রে উপযুক্ত বিকল্প।
মার্কো টপলনিক

এবং Pairঅন্যান্য উদাহরণে উল্লিখিত উদাহরণের মতো, তবে যুক্তির সীমা ছাড়াই।
বেনি বোত্তেমা

এছাড়াও আপনার এটিকে পরিবর্তনযোগ্য করতে হবে। (এবং hashCodeএকবার গণনা করুন )
রবআউ

2

আপনি অনেকগুলি ক্ষেত্রের জন্য শ্রেণিবদ্ধকারী হিসাবে তালিকাটি ব্যবহার করতে পারেন তবে youচ্ছিক ক্ষেত্রে আপনার নাল মানগুলি মোড়ানো দরকার:

Function<String, List> classifier = (item) -> List.of(
    item.getFieldA(),
    item.getFieldB(),
    Optional.ofNullable(item.getFieldC())
);

Map<List, List<Item>> grouped = items.stream()
    .collect(Collectors.groupingBy(classifier));

1

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

কেবল লক্ষ্য করার জন্য, আমি বাছাইটি ব্যবহার করিনি, যাতে এই উদাহরণটি বেশি জটিল না করে।

এটি আমার কোড:

@Test
public void test_2() throws Exception {
    Firm catering = DS.firm().get(1);
    LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
    LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
    Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
    Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

    List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
    Map<Object, Long> M = LON.stream().collect(
            Collectors.groupingBy(p
                    -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
                    Collectors.counting()));

    for (Map.Entry<Object, Long> e : M.entrySet()) {
        Object key = e.getKey();
        Long value = e.getValue();
        System.err.println(String.format("Client firm :%s, total: %d", key, value));
    }
}

0

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

    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     *
     * @author charudatta.joshi
     */
    public class Product1 {

        public BigInteger branchCode;
        public BigInteger prdId;
        public String accountCode;
        public BigDecimal actualBalance;
        public BigDecimal sumActBal;
        public BigInteger countOfAccts;

        public Product1() {
        }

        public Product1(BigInteger branchCode, BigInteger prdId, String accountCode, BigDecimal actualBalance) {
            this.branchCode = branchCode;
            this.prdId = prdId;
            this.accountCode = accountCode;
            this.actualBalance = actualBalance;
        }

        public BigInteger getCountOfAccts() {
            return countOfAccts;
        }

        public void setCountOfAccts(BigInteger countOfAccts) {
            this.countOfAccts = countOfAccts;
        }

        public BigDecimal getSumActBal() {
            return sumActBal;
        }

        public void setSumActBal(BigDecimal sumActBal) {
            this.sumActBal = sumActBal;
        }

        public BigInteger getBranchCode() {
            return branchCode;
        }

        public void setBranchCode(BigInteger branchCode) {
            this.branchCode = branchCode;
        }

        public BigInteger getPrdId() {
            return prdId;
        }

        public void setPrdId(BigInteger prdId) {
            this.prdId = prdId;
        }

        public String getAccountCode() {
            return accountCode;
        }

        public void setAccountCode(String accountCode) {
            this.accountCode = accountCode;
        }

        public BigDecimal getActualBalance() {
            return actualBalance;
        }

        public void setActualBalance(BigDecimal actualBalance) {
            this.actualBalance = actualBalance;
        }

        @Override
        public String toString() {
            return "Product{" + "branchCode:" + branchCode + ", prdId:" + prdId + ", accountCode:" + accountCode + ", actualBalance:" + actualBalance + ", sumActBal:" + sumActBal + ", countOfAccts:" + countOfAccts + '}';
        }

        public static void main(String[] args) {
            List<Product1> al = new ArrayList<Product1>();
            System.out.println(al);
            al.add(new Product1(new BigInteger("01"), new BigInteger("11"), "001", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("01"), new BigInteger("11"), "002", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "003", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "004", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "005", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("01"), new BigInteger("13"), "006", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("02"), new BigInteger("11"), "007", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("02"), new BigInteger("11"), "008", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "009", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "010", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "011", new BigDecimal("10")));
            al.add(new Product1(new BigInteger("02"), new BigInteger("13"), "012", new BigDecimal("10")));
            //Map<BigInteger, Long> counting = al.stream().collect(Collectors.groupingBy(Product1::getBranchCode, Collectors.counting()));
            // System.out.println(counting);

            //group by branch code
            Map<BigInteger, List<Product1>> groupByBrCd = al.stream().collect(Collectors.groupingBy(Product1::getBranchCode, Collectors.toList()));
            System.out.println("\n\n\n" + groupByBrCd);

             Map<BigInteger, List<Product1>> groupByPrId = null;
              // Create a final List to show for output containing one element of each group
            List<Product> finalOutputList = new LinkedList<Product>();
            Product newPrd = null;
            // Iterate over resultant  Map Of List
            Iterator<BigInteger> brItr = groupByBrCd.keySet().iterator();
            Iterator<BigInteger> prdidItr = null;    



            BigInteger brCode = null;
            BigInteger prdId = null;

            Map<BigInteger, List<Product>> tempMap = null;
            List<Product1> accListPerBr = null;
            List<Product1> accListPerBrPerPrd = null;

            Product1 tempPrd = null;
            Double sum = null;
            while (brItr.hasNext()) {
                brCode = brItr.next();
                //get  list per branch
                accListPerBr = groupByBrCd.get(brCode);

                // group by br wise product wise
                groupByPrId=accListPerBr.stream().collect(Collectors.groupingBy(Product1::getPrdId, Collectors.toList()));

                System.out.println("====================");
                System.out.println(groupByPrId);

                prdidItr = groupByPrId.keySet().iterator();
                while(prdidItr.hasNext()){
                    prdId=prdidItr.next();
                    // get list per brcode+product code
                    accListPerBrPerPrd=groupByPrId.get(prdId);
                    newPrd = new Product();
                     // Extract zeroth element to put in Output List to represent this group
                    tempPrd = accListPerBrPerPrd.get(0);
                    newPrd.setBranchCode(tempPrd.getBranchCode());
                    newPrd.setPrdId(tempPrd.getPrdId());

                    //Set accCOunt by using size of list of our group
                    newPrd.setCountOfAccts(BigInteger.valueOf(accListPerBrPerPrd.size()));
                    //Sum actual balance of our  of list of our group 
                    sum = accListPerBrPerPrd.stream().filter(o -> o.getActualBalance() != null).mapToDouble(o -> o.getActualBalance().doubleValue()).sum();
                    newPrd.setSumActBal(BigDecimal.valueOf(sum));
                    // Add product element in final output list

                    finalOutputList.add(newPrd);

                }

            }

            System.out.println("+++++++++++++++++++++++");
            System.out.println(finalOutputList);

        }
    }

আউটপুট নীচের হিসাবে রয়েছে:

+++++++++++++++++++++++
[Product{branchCode:1, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:1, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:1, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}, Product{branchCode:2, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:2, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:2, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}]

এটি বিন্যাস করার পরে:

[
Product{branchCode:1, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, 
Product{branchCode:1, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, 
Product{branchCode:1, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}, 
Product{branchCode:2, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, 
Product{branchCode:2, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, 
Product{branchCode:2, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}
]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.