Java:搜索对象数组列表以查找匹配ID但不同字段的有效方法
假设我有一个较大(>100000000)的Person数组列表,其中Person的定义如下:Java:搜索对象数组列表以查找匹配ID但不同字段的有效方法,java,algorithm,concurrency,java-stream,Java,Algorithm,Concurrency,Java Stream,假设我有一个较大(>100000000)的Person数组列表,其中Person的定义如下: class Person { public int id; public String name; } 我正在尝试编写一个方法,hasDuplicatePersonsWithDifferentNames(),如果ArrayList包含ID相同但名称不同的元素,则该方法返回true。例如: 这将返回true,因为有两个相同的ID具有不同的名称 ArrayList<Person>
class Person {
public int id;
public String name;
}
我正在尝试编写一个方法,hasDuplicatePersonsWithDifferentNames()
,如果ArrayList
包含ID相同但名称不同的元素,则该方法返回true
。例如:
这将返回true,因为有两个相同的ID具有不同的名称
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person(1, "bob");
people.add(new Person(1, "alice");
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person(1, "bob");
people.add(new Person(1, "bob");
ArrayList people=new ArrayList();
人员。添加(新人员(1,“bob”);
添加(新人物(1,“alice”);
这将返回false,因为虽然有两个相同的id,但它们共享相同的名称
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person(1, "bob");
people.add(new Person(1, "alice");
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person(1, "bob");
people.add(new Person(1, "bob");
ArrayList people=new ArrayList();
人员。添加(新人员(1,“bob”);
人员。添加(新人员(1,“bob”);
我在想会有一些方法来利用Java流,这是众所周知的高效方法,甚至可能是并发方法。但我找不到这两种方法的示例。我知道我可以使用字典在
O(n)中解决这个问题
时间/空间,但我相信使用streams/concurrency可以节省空间复杂性。问题在于您使用了错误的数据结构
如果你使用一个列表,那么搜索列表中的内容就需要迭代列表。在你的例子中,这意味着(可能)测试列表中的每个元素。所有1亿个元素
使用流或并发不会有帮助。您的代码仍然需要测试1亿个条目。(好的,并行搜索可以给您一个p
倍的速度,其中p
是可用的物理核心数。但是p
将是一个小而恒定的过程。)
因此,如果您想做得比O(N)
…更好,N
是一个非常大的数字…您需要一个支持基于元素字段的查找的数据结构。以下是一些可能性:
- 使用
并将其填充为从Map
到id
的映射。问题是Person
只能为每个键保存一个值,因此无法同时在映射中存储Bob和Alice。(但这可能是一个比当前更好的解决方案。) 如果使用Map
,则插入、删除和查找等操作都是HashMap
O(1)
- 使用多重映射。Apache Commons和Guava都提供多重映射类,或者您可以使用
map
- 上述两种方法使用的内存都比
多得多。另一种方法是根据ArrayList
对象的Person
值对列表进行排序,以便执行二进制搜索id
equals
和hashCode
。您可以将数据转换为哈希集,并比较初始列表和最终集的大小。如果没有,则可以使用映射
,其中id
作为键,name
s作为值,当y如果在映射中找到一个现有的键,则返回true
。在O(n)
运行时以下的时间内无法解决此问题,因为最坏的情况是(将迭代中的第一个和最后一个元素视为重复)。有了并发性,您可能唯一希望的就是分布式执行。您可以尝试toConcurrentMap
,将ID映射到键,将名称映射到值,并使用一个合并函数比较旧值和新值。如果它们相同,则将假原子布尔值设置为真。最后,检查原子布尔值是否正确olean。缺点是,这不是短路……当你想节省空间时,你必须放弃时间。使用考虑id和名称的比较器对列表进行排序。之后,你只需再次检查列表,并将一个元素与下一个元素进行比较。固定空间,但O(n log(n))时间。(请添加更多上下文:如果一开始就没有理由为一个ID使用多个名称,最好使用集合而不是列表,除非需要索引访问。)