从列表中查找最常见的对象

发布于 2024-10-18 13:34:55 字数 889 浏览 3 评论 0原文

假设我有一个 Employee 对象的 ListEmployee 对象有一个 getDepartment 方法,该方法返回一个 Department 对象。我想遍历该列表以找到拥有最多 Employee 的部门(即最常从 getDepartment 返回的 Department 对象)。最快的方法是什么?

public class Employee{

   static allEmployees = new ArrayList<Employee>();       

   int id;
   Department department;

   public Employee(int id, Department department){
     this.id = id;
     this.department = department;
     allEmployees.add(this);
   }

   public Department getDepartment(){
     return department;
   }

   public static List<Employee> getAllEmployees(){
      return allEmployees;
   }
}

public class Department{
   int id;
   String name;

   public Department(int id){
     this.id = id;
   }

   public String getName(){
     return name;
   }
}

如果两个部门的员工人数相同,则返回哪个部门并不重要。

谢谢!

Let's say I have a List of Employee Objects. The Employee Objects have a getDepartment method which returns a Department Object. I want to iterate through that list to find the department with the most Employees (i.e. the Department Object returned most often from getDepartment). What is the fastest way to do this?

public class Employee{

   static allEmployees = new ArrayList<Employee>();       

   int id;
   Department department;

   public Employee(int id, Department department){
     this.id = id;
     this.department = department;
     allEmployees.add(this);
   }

   public Department getDepartment(){
     return department;
   }

   public static List<Employee> getAllEmployees(){
      return allEmployees;
   }
}

public class Department{
   int id;
   String name;

   public Department(int id){
     this.id = id;
   }

   public String getName(){
     return name;
   }
}

If there's two departments with an equal number of employees it doesn't matter which is returned.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

居里长安 2024-10-25 13:34:55

创建部门 ID 的地图 ->很重要。

这样你就可以通过 id 获得所有计数的集合。您还可以维护一个最大项,它是对具有最高计数的映射条目的引用。

该算法类似于:

1) 初始化一个 Map 和一个 currentMax
2)循环遍历员工
3)对于每个员工,获取其部门ID
4)执行类似map.get(currentId)的操作
a) 如果当前计数为空,则初始化它
5) 增加计数
6)如果增加的计数>; currentMax, update currentMax

该算法将在 O(n) 内运行;我认为你没有比这更好的了。它的空间复杂度也是 O(n),因为计数的数量与输入的大小成正比。

如果您愿意,您可以创建一个使用组合(即包含一个映射和一个列表)的类,并且还管理保留指向具有最高计数的条目的指针。这样你的这部分功能就被正确封装了。这种方法的更大好处是,它允许您在将项目输入到列表中时维护计数(您可以代理将员工添加到列表中的方法,以便他们更新地图计数器)。但可能有点矫枉过正。

create a map of department id -> counts.

that way you get a collection of all the counts by id. You can also maintain a max item that is a reference to the map entry with the highest count.

the algorithm would be something like:

1) Initialize a Map and a currentMax
2) loop through employees
3) for each employee, get its department id
4) do something like map.get(currentId)
a) if the current count is null, initialize it
5) increment the count
6) if the incremented count is > currentMax, update currentMax

This algorithm will run in O(n); I don't think you can get any better than that. Its space complexity is also O(n) because the number of counts is proportional to the size of the input.

If you wanted, you could create a class that uses composition (i.e. contains a Map and a List) and also manages keeping pointers to the Entry with the highest count. That way this part of your functionality is properly encapsulated. The stronger benefit of this approach is it allows you to maintain the count as you enter items into the list (you would proxy the methods that add employees to the list so they update the map counter). Might be overkill though.

歌枕肩 2024-10-25 13:34:55

这是一个普通的 Java 8 解决方案:

Employee.getAllEmployees()
        .stream()
        .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()))
        .entrySet()
        .stream()
        .max(Comparator.comparing(Entry::getValue))
        .ifPresent(System.out::println);

它最多遍历员工列表两次。如果您愿意添加第三方依赖项,则使用 jOOλ 的等效解决方案如下

Seq.seq(Employee.getAllEmployees())
   .grouped(Employee::getDepartment, Agg.count())
   .maxBy(Tuple2::v2)
   .ifPresent(System.out::println);

:(免责声明:我在 jOOλ 背后的公司工作)

Here's a vanilla Java 8 solution:

Employee.getAllEmployees()
        .stream()
        .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()))
        .entrySet()
        .stream()
        .max(Comparator.comparing(Entry::getValue))
        .ifPresent(System.out::println);

It passes through the list of employees at most twice. An equivalent solution using jOOλ, if you're willing to add a third-party dependency, is this:

Seq.seq(Employee.getAllEmployees())
   .grouped(Employee::getDepartment, Agg.count())
   .maxBy(Tuple2::v2)
   .ifPresent(System.out::println);

(Disclaimer: I work for the company behind jOOλ)

墨小沫ゞ 2024-10-25 13:34:55

我会使用 Guava 执行类似的操作:

Multiset<Department> departments = HashMultiset.create();
for (Employee employee : employees) {
  departments.add(employee.getDepartment());
}

Multiset.Entry<Department> max = null;
for (Multiset.Entry<Department> department : departments.entrySet()) {
  if (max == null || department.getCount() > max.getCount()) {
    max = department;
  }
}

您需要正确实现 equalshashCodeDepartment 上才能正常工作。

这里还有一个问题提到了创建未来的“排行榜”类型 Multiset 将根据其包含的每个条目的数量来维护订单。

I would do something like this using Guava:

Multiset<Department> departments = HashMultiset.create();
for (Employee employee : employees) {
  departments.add(employee.getDepartment());
}

Multiset.Entry<Department> max = null;
for (Multiset.Entry<Department> department : departments.entrySet()) {
  if (max == null || department.getCount() > max.getCount()) {
    max = department;
  }
}

You would need a correct implementation of equals and hashCode on Department for this to work.

There's also an issue here that mentions the possibility of creating a "leaderboard" type Multiset in the future that would maintain an order based on the count of each entry it contains.

如果没有 2024-10-25 13:34:55

由于您只想统计员工数量,因此制作地图相对容易。

HashMap<Department, Integer> departmentCounter;

将部门映射到员工数量(您增加每个员工的计数)。或者,您可以使用列表将整个 Employee 存储在地图中:

HashMap<Department, List<Employee>> departmentCounter;

并查看列表的大小。

如果你不知道如何使用该类,可以查看HashMap文档:
http://download.oracle.com/javase /1.4.2/docs/api/java/util/HashMap.html

提示:您需要使用 HashMap.keySet() 来查看已输入哪些部门。

Since you just want to count employees, it's relatively easy to make a map.

HashMap<Department, Integer> departmentCounter;

that maps Departments to the number of employees (you increment the count for every employee). Alternatively, you can store the whole Employee in the map with a list:

HashMap<Department, List<Employee>> departmentCounter;

and look at the size of your lists instead.

Then you can look at the HashMap documentation if you don't know how to use the class:
http://download.oracle.com/javase/1.4.2/docs/api/java/util/HashMap.html

Hint: you will need to use HashMap.keySet() to see which departments have been entered.

樱花细雨 2024-10-25 13:34:55

我会这样做,modulo == null 和 isEmpty 检查:

public static <C> Multimap<Integer, C> getFrequencyMultimap(final Collection<C> collection,
    final Ordering<Integer> ordering) {
    @SuppressWarnings("unchecked")
    Multimap<Integer, C> result = TreeMultimap.create(ordering, (Comparator<C>) Ordering.natural());
    for (C element : collection) {
        result.put(Collections.frequency(collection, element), element);
    }
    return result;
}

public static <C> Collection<C> getMostFrequentElements(final Collection<C> collection)       {
    Ordering<Integer> reverseIntegerOrdering = Ordering.natural().reverse();
    Multimap<Integer, C> frequencyMap = getFrequencyMultimap(collection, reverseIntegerOrdering);
    return frequencyMap.get(Iterables.getFirst(frequencyMap.keySet(), null));
}

还有 CollectionUtils.getCardinalityMap() 它将完成第一种方法的工作,但这更灵活更偏向番石榴。

请记住,C 类应该得到很好的实现,即具有 equals()、hashCode() 并实现 Comparable。

这是您可以使用它的方式:

Collection<Dummy> result = LambdaUtils.getMostFrequentElements(list);

作为奖励,您还可以使用类似的方法获取频率较低的元素,只需使用 Ordering.natural() 提供第一个方法并且不要反转它。

I would do it like that, modulo == null and isEmpty checks:

public static <C> Multimap<Integer, C> getFrequencyMultimap(final Collection<C> collection,
    final Ordering<Integer> ordering) {
    @SuppressWarnings("unchecked")
    Multimap<Integer, C> result = TreeMultimap.create(ordering, (Comparator<C>) Ordering.natural());
    for (C element : collection) {
        result.put(Collections.frequency(collection, element), element);
    }
    return result;
}

public static <C> Collection<C> getMostFrequentElements(final Collection<C> collection)       {
    Ordering<Integer> reverseIntegerOrdering = Ordering.natural().reverse();
    Multimap<Integer, C> frequencyMap = getFrequencyMultimap(collection, reverseIntegerOrdering);
    return frequencyMap.get(Iterables.getFirst(frequencyMap.keySet(), null));
}

There is also CollectionUtils.getCardinalityMap() which will do the job of the first method, but this is more flexible and more guavish.

Just keep in mind that the C class should be well implemented, that is have equals(), hashCode() and implement Comparable.

This is how you can use it:

Collection<Dummy> result = LambdaUtils.getMostFrequentElements(list);

As a bonus, you can also get the less frequent element with a similar method, just, feed the first method with Ordering.natural() and do not reverse it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文