如何使用 Java 在给定列表中查找重复项中最大数字的索引

How to find the indexes of the biggest number in a given List with duplicates using Java

我有一个包含值 [1,2,2,8,7,8] 的列表。我想找到最大数字的索引。这里最大的数字是 8。8 重复了两次。所以答案应该是 [3,5] 即两个 8 的索引。

我花了很多时间。我能够找到最大的数字。我无法找到一个干净简单的解决方案来查找索引。

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<Integer> parts = new ArrayList<>();
        parts.add(1);
        parts.add(2);
        parts.add(2);
        parts.add(8);
        parts.add(7);
        parts.add(8);

        Test ob = new Test();
        System.out.println("Indexs with max value:" + ob.getIndex(parts));
    }

    public List<Integer> getIndex(List<Integer> parts) {
        int big = parts.get(0);
        List<Integer> indexes = new ArrayList<>();
        for (int i = 1; i < parts.size(); i++) {
            if (big <= parts.get(i)) {
                big = parts.get(i);
                indexes.add(i);
            }
        }
        System.out.println("Biggest Number:" + big);
        return indexes;
    }
}

上面的代码打印了最大的数字并打印了错误的索引,即每当它进入 if 循环时,我都会向索引添加 'i' 值。我需要过滤,以便仅在值很大时才添加。我正在寻找没有两个 for 循环的解决方案。感谢任何帮助。

你快到了;当你遇到一个新的“最大”数字时,你只需要清除列表。您可以通过像这样添加到 if 语句来做到这一点:

        if (big <= parts.get(i)) {

            // new biggest number, so previous indexes no longer apply
            if (big < parts.get(i)) {
                indexes.clear();
            }

            big = parts.get(i);
            indexes.add(i);
        }

您快到了,您只是在找到更大的数字时忘记清理您的列表:

for (int i = 0; i < parts.size(); i++) {
    if (big <= parts.get(i)) {
        if (big < parts.get(i)) {
            indexes.clear();
        }
        big = parts.get(i);
        indexes.add(i);
    }
}

一个更优雅但也有点慢的解决方案是使用 Streams:

public List<Integer> getIndex(List<Integer> parts)
    if (!parts.isEmpty()) {
        int max = parts.stream().max(Integer::compare).get();
        return IntStream.range(0, parts.size())
                .filter(i -> parts.get(i) == max)
                .boxed()
                .collect(Collectors.toList());
    }
    return Collections.emptyList();
}

遇到新的“最大”数字时重新创建 indexes 列表,将该索引添加到新列表(或清除列表并添加新索引)。如果数字等于当前“最大”数字,则将索引添加到列表中。

public List<Integer> getIndex(List<Integer> parts) {
    int big = parts.get(0);
    List<Integer> indexes = new ArrayList<>();
    for (int i = 1; i < parts.size(); i++) {
        if (big < parts.get(i)) {
            // new biggest, create new list starting with this index
            big = parts.get(i);
            indexes = new ArrayList<>();
            indexes.add(i);
        } else if (big == parts.get(i)) {
            // new instance, add index
            indexes.add(i);
        } // else do nothing, not bigger or instance of current biggest 
    }
    System.out.println("Biggest Number:" + big);
    return indexes;
}

结果:

Biggest Number:8
Indices with max value:[3, 5]

  1. 你需要清除你每次发现值大于大时索引列表。
  2. 你需要添加索引到索引如果大并且parts.get(i) == big
  3. 您需要检查零件是否为空。
  4. 您需要在循环之前添加 索引 0 到索引中,因为部分只能包含一个元素。

这是代码:

public List<Integer> getIndex(List<Integer> parts) {
    List<Integer> indexes = new ArrayList<>();
    if (!parts.isEmpty()) {
        int big = parts.get(0);
        indexes.add(0);
        for (int i = 1; i < parts.size(); i++) {
            if (big < parts.get(i)) {
                big = parts.get(i);
                indexes.clear();
                indexes.add(i);
            } else if (big == parts.get(i)) {

                indexes.add(i);
            }
        }
    }
    return indexes;
}

输出,在你的例子中:

Indexs with max value:[3, 5]

它可以使用带有键的排序映射来解决 - 输入列表的元素,以及值 - 索引列表。

TreeMap<Integer, List<Integer>> valueIndexes = new TreeMap<>();

索引列表可以created/populated不同的方式:

List<Integer> list = Arrays.asList(1, 2, 2, 8, 7, 8);

for (int i = 0; i < list.size(); i++) {
    List<Integer> indexes = valueIndexes.computeIfAbsent(list.get(i), (x) -> new ArrayList<>());
    indexes.add(i);
}
System.out.println("valueIndexes: " + valueIndexes.lastEntry().getValue()); // lastEntry may be null for empty input list 
  • Map::merge不太方便,因为创建了很多中间列表:
for (int i = 0; i < list.size(); i++) {
    valueIndexes.merge(
        list.get(i),                       // key: element of input
        new ArrayList<>(Arrays.asList(i)), // store index into extendable list
        (l1, l2) -> { l1.addAll(l2); return l1; } // merge function
    );
}
System.out.println("merge valueIndexes: " + valueIndexes.lastEntry().getValue()); 

类似地,可以从使用 Collectors.groupingBy + Collectors.mapping 创建的 未排序 映射中选择最大元素,然后选择最大键和相关索引列表:

List<Integer> maxIndexes = IntStream.range(0, list.size())
       .boxed()
       .collect(Collectors.groupingBy(i -> list.get(i), 
                Collectors.mapping(i -> i, Collectors.toList()) // build list of indexes
       ))
       .entrySet()
       .stream()
       .collect(Collectors.maxBy(Map.Entry.comparingByKey()))
       .orElse(Map.entry(-1, Collections.emptyList())).getValue();
System.out.println(maxIndexes);

可以结合使用这些方法来从收集器检索到的已排序映射中获取最后一个条目:

List<Integer> maxIndexes2 = IntStream.range(0, list.size())
       .boxed()
       .collect(Collectors.groupingBy(i -> list.get(i), TreeMap::new,
                Collectors.mapping(i -> i, Collectors.toList())
        ))
       .lastEntry().getValue();
System.out.println(maxIndexes2);