比较两个列表基于最高值和随后的值?

huangapple go评论71阅读模式
英文:

Compare two lists based on highest value and subsequent values?

问题

我想比较每个列表,找到每个列表中的“最高”分数。如果两个最高分数相同,那么我想比较第二高分数,依此类推。我该怎么做?

英文:

I have two lists of:

List<Person> persons;

each Person has the attribute - score

e.g.

list1:

person.score = 3
person.score = 5
person.score = 8

list2:

person.score = 8
person.score = 4
person.score = 7

I want to compare each list to find the highest score in each. If both highest are the same, then I want to compare the second highest etc and so on.

How can I do so?

答案1

得分: 1

你可以复制每个 List,对这些副本进行排序,然后逐个元素进行比较。

英文:

You can make a copy of each List, sort these copies, then compare them element by element.

Comparator<List<Person>> comp = (a, b) -> {
    List<Person> s1 = a.stream().sorted(Comparator.comparingInt(Person::getScore).reversed()).toList(), 
                 s2 = b.stream().sorted(Comparator.comparingInt(Person::getScore).reversed()).toList();
    for (int i = 0; i < Math.min(a.size(), b.size()); i++) {
        int c = Integer.compare(s1.get(i).getScore(), s2.get(i).getScore());
        if (c != 0) return c;
    }
    return Integer.compare(a.size(), b.size());
};

答案2

得分: 0

定义一个比较器来比较这些列表。在排序每个列表后,比较器会在相应的分数不相等时提前终止,返回最后一次比较的值。否则,如果两个列表相等,或者它们的大小不同,较短的列表将返回为较小的。

细节

由于分数是比较的目标,我决定提前获取它并将其放在已排序的int数组中。然后我反向迭代这些数组,以确保我首先测试最大的元素(IntStreams不能采用比较器进行排序,而且我不想包装int值)。

在遍历列表时,分数进行比较,并将结果映射到流中。然后比较的结果(-1、0或1)被过滤以忽略零值,将结果捕获在OptionalInt中。

然后要么返回OptionalInt值,要么比较数组大小。然后,如果所有比较都相等,较小的数组长度将返回-1,较大的将返回1,相等的长度将返回0。

Comparator<List<Person>> listComp = (lst1, lst2) -> {
    int[] scores1 = lst1.stream().mapToInt(Person::getScore).sorted()
            .toArray();
    int[] scores2 = lst2.stream().mapToInt(Person::getScore).sorted()
            .toArray();
    
    OptionalInt diff = IntStream
            .iterate(Math.min(scores1.length-1, scores2.length-1),
                    i -> i >= 0, i -> i-1)
            .map(i -> Integer.compare(scores1[i], scores2[i]))
            .filter(delta -> delta != 0).findFirst();

    return diff.orElse(Integer.compare(scores1.length, scores2.length));
};

演示

一些数据 - 比较列表中的每两个列表。出于演示目的,我使用了一个具有修改的toString()record

record Person(int getScore) {
    @Override
    public String toString() {
        return "%d".formatted(getScore);
    }
}

List<List<Person>> lists = List.of(
        // 第一个较小
        List.of(new Person(3), new Person(5), new Person(8)),
        List of(new Person(8), new Person(4), new Person(7)),
        // 相等的列表
        List of(new Person(3), new Person(7), new Person(8)),
        List of(new Person(8), new Person(3), new Person(7)),
        // 由于长度而较小
        List of(new Person(3), new Person(7), new Person(8)),
        List of(new Person(8), new Person(3), new Person(7),
                new Person(2)));

要比较这些列表,请使用int result = listComp.compare(list1, list2);

int v;
for (int i = 0; i < lists.size(); i += 2) {
    System.out.println(lists.get(i)
            + ((v = listComp.compare(lists.get(i), lists.get(i + 1))) > 0
                    ? " > "
                    : (v < 0) ? " < " : " == ")
            + lists.get(i + 1));
}

输出如下:

[3, 5, 8] < [8, 4, 7]
[3, 7, 8] == [8, 3, 7]
[3, 7, 8] > [8, 3, 7, 2]
英文:

Define a comparator to compare the lists. After, sorting each list, The comparator short circuits as soon corresponding scores are unequal, returning the value of the the last comparison. Otherwise, if the two lists are equal or if if their sizes are different, the shortest list will return as the smaller.

Details

Since the score is the target of the comparison, I decided to grab it early and place in int arrays which are sorted. Then I iterate over the arrays in reverse order to ensure I am testing the largest elements first (IntStreams can't take a comparator for sorting and I didn't want to box the int values).

Iterating over the lists, the scores are compared and the result is mapped to the stream. Then the result of the comparison (-1,0, or 1) is filtered to ignore zero values, capturing the result in an OptionalInt.

Then either the OptionalInt value is returned, or the comparison of the array sizes. Then, all comparisons being equal, the smaller array length would return -1, larger 1, and equal lengths 0

Comparator&lt;List&lt;Person&gt;&gt; listComp = (lst1, lst2) -&gt; {
    int[] scores1 = lst1.stream().mapToInt(Person::getScore).sorted()
            .toArray();
    int[] scores2 = lst2.stream().mapToInt(Person::getScore).sorted()
            .toArray();
    
    OptionalInt diff = IntStream
            .iterate(Math.min(scores1.length-1, scores2.length-1),
                    i -&gt; i &gt;= 0, i -&gt; i-1)
            .map(i -&gt; Integer.compare(scores1[i], scores2[i]))
            .filter(delta -&gt; delta != 0).findFirst();

    return diff.orElse(Integer.compare(scores1.length, scores2.length));
};

Demos

Some Data - comparing every two lists in the list of lists to each other. For demo purposes, I am using a record with a modified toString().

record Person(int getScore) {
     @Override
     public String toString() {
         return &quot;%d&quot;.formatted(getScore);
     }
}

List&lt;List&lt;Person&gt;&gt; lists = List.of(
        // first is smaller
        List.of(new Person(3), new Person(5), new Person(8)),
        List.of(new Person(8), new Person(4), new Person(7)),
        // equal lists
        List.of(new Person(3), new Person(7), new Person(8)),
        List.of(new Person(8), new Person(3), new Person(7)),
        // first is smaller due to length
        List.of(new Person(3), new Person(7), new Person(8)),
        List.of(new Person(8), new Person(3), new Person(7),
                new Person(2)));

To compare the lists, use int result = listComp.compare(list1, list2);

 int v;
 for (int i = 0; i &lt; lists.size(); i += 2) {
     System.out.println(lists.get(i)
             + ((v = listComp.compare(lists.get(i), lists.get(i + 1))) &gt; 0
                     ? &quot; &gt; &quot;
                     : (v &lt; 0) ? &quot; &lt; &quot; : &quot; == &quot;)
             + lists.get(i + 1));
 }

prints the following:

[3, 5, 8] &lt; [8, 4, 7]
[3, 7, 8] == [8, 3, 7]
[3, 7, 8] &gt; [8, 3, 7, 2]



</details>



huangapple
  • 本文由 发表于 2023年2月18日 00:56:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75487147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定