【问题标题】:Finding multiple min/max using Collections.min/max使用 Collections.min/max 查找多个最小值/最大值
【发布时间】:2018-09-11 10:42:46
【问题描述】:

在我正在处理的一个示例中,我试图找到列表中最小的三个元素(不对列表进行排序),然后将这三个元素添加到一个新列表中。

因为这是一个示例,我可以简单地使用 for 循环,使用 Collections.min(list) 将该元素添加到新列表中,然后从原始列表中删除该元素。如果我没有删除该元素,我将获得相同的元素 3 次。但是,通过删除元素,我得到了我想要的结果。

如何在不从列表中删除最大/最小元素的情况下执行此操作?

【问题讨论】:

  • 为什么不能对列表进行排序?我们可以假设您要保留整数或实数自然数吗?

标签: java collections min


【解决方案1】:

如果你想找到最大/最小 3 个元素,我建议你使用 PriorityQueue:

PriorityQueue<Integer> pq = new PriorityQueue<>(k);

然后在一个循环中,将元素添加到这个队列中。

然后您可以通过从队列中删除将这 3 个元素添加到列表中,然后简单地从方法中返回。

更好的是使用 3 个单独的变量并直接在主列表上循环。 注意:如果您稍后将 3 更新为其他值,此方法将不可行。而PriorityQueue 方法将是灵活的。

public static void main (String[] args) throws java.lang.Exception {
    Integer arr[] = {2, 6, 5, 3, 7, 9, 12, 35, 1, 3};
    List<Integer> incoming = Arrays.asList(arr);
    Comparator<Integer> maxFirstComparator = (x, y) -> Integer.compare(y,x);
    printList(getMinOrMaxKNumbers(incoming, 3, null));
    System.out.println();
    printList(getMinOrMaxKNumbers(incoming, 3, maxFirstComparator));
}

/*
 * gets the max/min K elements from the List
 * @param comparator    if null is passed the method uses natural ordering
 *
 */
private static List<Integer> getMinOrMaxKNumbers(List<Integer> incoming, int k, Comparator<Integer> comparator) {
    int n = incoming.size();
    PriorityQueue<Integer> pq = comparator == null ? new PriorityQueue<>(n) : new PriorityQueue<>(n, comparator);

    for (int i : incoming) {
        pq.add(i);
    }

    List<Integer> outgoing = new ArrayList<>(k);
    for (int i = 0; i < k; i++) {
        outgoing.add(pq.poll());
    }

    return outgoing;
}

private static void printList(List<Integer> list) {
    list.stream().forEach(x -> System.out.print(x + " "));
}

【讨论】:

    【解决方案2】:

    我认为没有任何直接的方法可以使用标准库来做到这一点。

    以下代码包含一个实用方法,用于获取最大元素数的集合。

    它的工作原理是将最大元素保存在TreeSet 中,只有当它属于最大元素时才会将元素插入其中。树集非常适合这里,因为它可以快速找到最小元素,并测试一个元素是否包含在集合中。

    通过这种方式,您可以获得良好的性能,并且可以灵活地使用所需的最大元素数量。

    public class MultipleMaxElements {
        public static void main(String[] args) {
            List<Integer> l = List.of(4, 2, 5, 8, 2, 8, 0, 1);
    
            System.out.println(maxElements(l, 3, Comparator.naturalOrder()));
            System.out.println(maxElements(l, 3, Comparator.<Integer>naturalOrder().reversed()));
        }
    
        public static <T> Set<T> maxElements(Iterable<T> list, int nrElems, Comparator<T> cmp) {
            TreeSet<T> maxSet = new TreeSet<>(cmp);
    
            for (T elem : list) {
                if (maxSet.size() < nrElems) {
                    maxSet.add(elem);
                } else if (!maxSet.contains(elem) && cmp.compare(elem, maxSet.first()) > 0) {
                    maxSet.pollFirst();
                    maxSet.add(elem);               
                }
            }
    
            return maxSet;
        }
    }
    

    在问题文本中,您没有写任何关于如何处理输入列表中的重复元素的内容。此方法返回最大的唯一元素。

    如果应保留重复项,则可以使用基于树的 Guava 多集而不是普通的 TreeSet

    【讨论】:

      猜你喜欢
      • 2022-09-29
      • 1970-01-01
      • 2012-09-16
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-20
      • 2020-08-29
      相关资源
      最近更新 更多