使用集合查找多个 min/max。min/max
Finding multiple min/max using Collections.min/max
在我处理的一个示例中,我尝试在列表中找到最小的三个元素(不对列表进行排序),然后将这三个元素添加到新列表中。
因为这是一个示例,所以我可以简单地使用 for 循环,使用 Collections.min(list)
将该元素添加到新列表,然后从原始列表中删除该元素。如果我没有删除该元素,我将获得相同的元素三次。但是,通过删除元素,我得到了我想要的结果。
如何在不从列表中删除 max/min 元素的情况下执行此操作?
如果你想找到 max/min 3 个元素,我建议你使用 PriorityQueue
:
PriorityQueue<Integer> pq = new PriorityQueue<>(k);
然后在一个循环中,向这个队列添加元素。
然后您可以通过从队列中删除并简单地从方法中 return 将这 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 + " "));
}
我认为使用标准库没有任何直接的方法可以做到这一点。
以下代码包含一个实用方法来获取一组最大元素。
它的工作原理是将最大元素保留在 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;
}
}
在问题文本中,您没有写任何关于应如何处理输入列表中的重复元素的内容。此方法 returns 最大唯一元素。
如果应保留重复项,则可以使用基于树的 Guava multi-set 而不是普通的 TreeSet
。
在我处理的一个示例中,我尝试在列表中找到最小的三个元素(不对列表进行排序),然后将这三个元素添加到新列表中。
因为这是一个示例,所以我可以简单地使用 for 循环,使用 Collections.min(list)
将该元素添加到新列表,然后从原始列表中删除该元素。如果我没有删除该元素,我将获得相同的元素三次。但是,通过删除元素,我得到了我想要的结果。
如何在不从列表中删除 max/min 元素的情况下执行此操作?
如果你想找到 max/min 3 个元素,我建议你使用 PriorityQueue
:
PriorityQueue<Integer> pq = new PriorityQueue<>(k);
然后在一个循环中,向这个队列添加元素。
然后您可以通过从队列中删除并简单地从方法中 return 将这 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 + " "));
}
我认为使用标准库没有任何直接的方法可以做到这一点。
以下代码包含一个实用方法来获取一组最大元素。
它的工作原理是将最大元素保留在 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;
}
}
在问题文本中,您没有写任何关于应如何处理输入列表中的重复元素的内容。此方法 returns 最大唯一元素。
如果应保留重复项,则可以使用基于树的 Guava multi-set 而不是普通的 TreeSet
。