簡體   English   中英

如何將集合中的所有對象與同一集合中的所有對象進行比較?

[英]How do I compare all objects in a collection against all objects in the same collection?

如何將集合中的所有對象與同一集合中的所有其他對象進行比較? 我目前將 for 循環與另一個嵌套的 for 循環一起使用。 但是,這很慢,我想優化我的方法。

請參閱下面的示例。 具體來說,如何優化personsGroupedByFirstName方法? 該方法檢索Person列表並將其轉換為 map ,其中每個Person與具有相同firstName的其他人分組。

謝謝。

import java.util.*;

class Scratch {
    public static void main(String[] args) {
        new Scratch().start();
    }

    public void start() {
        List<Person> persons = getPersons();
        Map<String, List<Person>> stacks = personsGroupedByFirstName(persons);

        for (Map.Entry<String, List<Person>> entrySet : stacks.entrySet()) {
            String key = entrySet.getKey();
            List<Person> value = entrySet.getValue();

            System.out.println("First name: " + key);
            System.out.println("People: " + value);
        }
    }

    private List<Person> getPersons() {
        return List.of(
                new Person("Andrew", "Red"), new Person("Bob", "Red"),
                new Person("Craig", "Red"), new Person("Daniel", "Red"),
                new Person("Andrew", "Yellow"), new Person("Bob", "Yellow"),
                new Person("Craig", "Yellow"), new Person("Daniel", "Yellow"),
                new Person("Andrew", "Pink"), new Person("Bob", "Pink"),
                new Person("Craig", "Pink"), new Person("Daniel", "Pink"),
                new Person("Andrew", "Green"), new Person("Bob", "Green"),
                new Person("Craig", "Green"), new Person("Daniel", "Green"),
                new Person("Andrew", "Orange"), new Person("Bob", "Orange"),
                new Person("Craig", "Orange"), new Person("Daniel", "Orange"),
                new Person("Andrew", "Purple"), new Person("Bob", "Purple"),
                new Person("Craig", "Purple"), new Person("Daniel", "Purple"),
                new Person("Andrew", "Blue"), new Person("Bob", "Blue"),
                new Person("Craig", "Blue"), new Person("Daniel", "Blue")
        );
    }

    private Map<String, List<Person>> personsGroupedByFirstName(List<Person> persons) {
        Map<String, List<Person>> stacks = new HashMap<>();

        int loop = 0;
        for (Person outer : persons) {
            if (!outer.isReachable()) {
                continue;
            }

            String outerFirstName = outer.getFirstName();
            List<Person> stack = new ArrayList<>();
            for (Person inner : persons) {
                loop = loop + 1;
                if (!inner.isReachable()) {
                    continue;
                }

                if (isSimilar(outerFirstName, inner.getFirstName())) {
                    inner.setReachable(false);
                    stack.add(inner);
                }
            }

            List<Person> tmp = stacks.get(outerFirstName);
            if (tmp == null) {
                tmp = new ArrayList<>();
            }

            tmp.addAll(stack);
            stacks.put(outerFirstName, tmp);
        }

        System.out.println("Total Loops: " + loop);
        return stacks;
    }

    /*
     * Trivial condition. My actual use case computes the Levenshtein Distance.
     * */
    private boolean isSimilar(String outerFirstName, String outerSecondName) {
        return outerFirstName.equals(outerSecondName);
    }
}

class Person {
    private final String firstName;
    private final String secondName;
    private boolean reachable = true;

    public Person(String firstName, String secondName) {
        this.firstName = firstName;
        this.secondName = secondName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getSecondName() {
        return secondName;
    }

    public boolean isReachable() {
        return reachable;
    }

    public void setReachable(boolean reachable) {
        this.reachable = reachable;
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", secondName='" + secondName + '\'' +
                '}';
    }
}

根本不需要執行兩個嵌套循環。 您是按屬性分組,而不是“將每個 object 相互比較”。 您用來存儲結果的 map 已經通過密鑰記住了所有遇到的對象。

你可以簡單地使用

private Map<String, List<Person>> personsGroupedByFirstName(List<Person> persons) {
    Map<String, List<Person>> result = new HashMap<>();

    for(Person p: persons) {
        List<Person> list = result.get(p.getFirstName());
        if(list == null) {
            list = new ArrayList<>();
            result.put(p.getFirstName(), list);
        }
        list.add(p);
    }
    return result;
}

我假設這個isReachable()測試是為了優化你的兩個嵌套循環,而不是實際任務的一部分。

當您熟悉 lambda 表達式后,您可以進一步簡化此循環,在 map 上使用單個操作,而不是getput

private Map<String, List<Person>> personsGroupedByFirstName(List<Person> persons) {
    Map<String, List<Person>> result = new HashMap<>();

    for(Person p: persons) {
        List<Person> list
            = result.computeIfAbsent(p.getFirstName(), key -> new ArrayList<>());
        list.add(p);
    }
    return result;
}

使用 Stream API 的等效操作是

private Map<String, List<Person>> personsGroupedByFirstName(List<Person> persons) {
    return persons.stream()
        .collect(Collectors.groupingBy(Person::getFirstName));
}

groupingBy(Person::getFirstName)groupingBy(Person::getFirstName, toList())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM