首页 > 编程知识 正文

javalist去重,JAVA获取list重复对象

时间:2023-05-04 19:02:26 阅读:32625 作者:4513

问题

如今,互联网技术成熟,越来越多的趋势趋向于去中心化、分布式化、流媒体计算,很多以前在数据库方面做的事情都放在Java方面。 如果今天数据库字段没有索引,该如何根据该字段重新定位? 用Java做的话大家都一致,怎么办?

解答

突然想起以前写list去重的文章,试着找了一下。 方法是重写列表中对象的hashcode和equals方法,使其落入HashSet中,然后将其检索。 这是最初学Java时像字典一样背诵写的答案。 例如在面试中,我遇到过一个自称做了三年Java的人。 虽然可以背诵Set和HashMap的区别,但是问怎么实现就不知道了。 也就是说,初学者只背特性。 但是,真正在项目中使用的时候,需要确认是否真的是这样。 背书没有用,所以只能相信结果。 我需要知道HashSet是怎么帮助我的。 换个想法,可以不使用HashSet而去重物吗? 最简单、最直接的方法不是每次都拿着和历史数据进行比较,而是如果一切都不一样的话,插入到团队的最后。 HashSet只是加快了这个过程。

首先,指示要排序的用户

@Data

@Builder

@AllArgsConstructor

公共类用户{

私有integer id;

私有字符串名称;

}

List users=Lists.newArrayList (

新用户(1,' a )、

新用户(1,' b )、

新用户(2,' b '表示,

新用户(1,' a ' );

目标可以通过检索id不重复的用户,给出防止剥皮的规则,任意检索id唯一的数据即可,不局限于在id相同的情况下计算哪个。

用最直观的方法

此方法是用空列表保存扫描后的数据。

@Test

公共语音dis1() {

列表结果=new linked list (;

for (用户:用户) {

boolean b=result.stream ().any match (u-u.getid ).equals(user.getid ) );

if (! b ) {

result.add (用户;

}

}

system.out.println(result );

}

使用HashSet

背诵特性的人知道HashSet会变重,但怎么会变重呢? 再深入一点的背诵依据hashcode和equals方法。 那么是怎么根据这两个做的呢? 没有看过源代码的人不能继续下去。 面试也到此结束。

实际上,HashSet是通过HashMap实现的。 (当我没有看到源代码时,我直观地认为HashMap中的key是由HashSet实现的,但正好相反。 在此不展开记述,只要看HashSet的结构方法和add方法就可以理解。

公共散列()。

map=new HashMap (;

}

//*

*很明显,如果存在则返回false,如果不存在则返回true

*/

publicbooleanadd{

returnmap.put(e,PRESENT )==null;

}

由此可见,混叠的重复是通过混叠来实现的,混叠的实现完全依赖于混叠和质量的方法。 这样就完全明白了。 要使用HashSet,你必须看到自己的这两种方法。

在这个主题中,需要根据id来消除重量。 那么,我们比较的依据是id。 修改如下。

@Override

publicbooleanequals (对象) {

if(this==o ) {

返回真;

}

if(o==null||getclass (!=o.getClass () ) }

返回假;

}

用户=(用户) o;

返回对象. equals (id,user.id );

}

@Override

公共int hashcode (

returnobjects.hash(id;

}

//hashcode

结果=31 *结果(element==null? 0 : element.hashCode ();

其中,Objects调用了Arrays的hashcode,内容如上。 乘以31等于x5

-x。

最终实现如下:

@Test

public void dis2() {

Set result = new HashSet<>(users);

System.out.println(result);

}

使用Java的Stream去重

回到最初的问题,之所以提这个问题是因为想要将数据库侧去重拿到Java端,那么数据量可能比较大,比如10w条。对于大数据,采用Stream相关函数是最简单的了。正好Stream也提供了distinct函数。那么应该怎么用呢?

users.parallelStream().distinct().forEach(System.out::println);

没看到用lambda当作参数,也就是没有提供自定义条件。幸好Javadoc标注了去重标准:

Returns a stream consisting of the distinct elements

(according to {@link Object#equals(Object)}) of this stream.

我们知道,也必须背过这样一个准则:equals返回true的时候,hashcode的返回值必须相同. 这个在背的时候略微有些逻辑混乱,但只要了解了HashMap的实现方式就不会觉得拗口了。HashMap先根据hashcode方法定位,再比较equals方法。

所以,要使用distinct来实现去重,必须重写hashcode和equals方法,除非你使用默认的。

那么,究竟为啥要这么做?点进去看一眼实现。

Node reduce(PipelineHelper helper, Spliterator spliterator) {

// If the stream is SORTED then it should also be ORDERED so the following will also

// preserve the sort order

TerminalOp> reduceOp

= ReduceOps.>makeRef(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll);

return Nodes.node(reduceOp.evaluateParallel(helper, spliterator));

}

内部是用reduce实现的啊,想到reduce,瞬间想到一种自己实现distinctBykey的方法。我只要用reduce,计算部分就是把Stream的元素拿出来和我自己内置的一个HashMap比较,有则跳过,没有则放进去。其实,思路还是最开始的那个最直白的方法。

@Test

public void dis3() {

users.parallelStream().filter(distinctByKey(User::getId))

.forEach(System.out::println);

}

public static Predicate distinctByKey(Function super T, ?> keyExtractor) {

Set seen = ConcurrentHashMap.newKeySet();

return t -> seen.add(keyExtractor.apply(t));

}

当然,如果是并行stream,则取出来的不一定是第一个,而是随机的。

上述方法是至今发现最好的,无侵入性的。但如果非要用distinct。只能像HashSet那个方法一样重写hashcode和equals。

小结

会不会用这些东西,你只能去自己练习过,不然到了真正要用的时候很难一下子就拿出来,不然就冒险用。而若真的想大胆使用,了解规则和实现原理也是必须的。比如,LinkedHashSet和HashSet的实现有何不同。

附上贼简单的LinkedHashSet源码:

public class LinkedHashSet

extends HashSet

implements Set, Cloneable, java.io.Serializable {

private static final long serialVersionUID = -2851667679971038690L;

public LinkedHashSet(int initialCapacity, float loadFactor) {

super(initialCapacity, loadFactor, true);

}

public LinkedHashSet(int initialCapacity) {

super(initialCapacity, .75f, true);

}

public LinkedHashSet() {

super(16, .75f, true);

}

public LinkedHashSet(Collection extends E> c) {

super(Math.max(2*c.size(), 11), .75f, true);

addAll(c);

}

@Override

public Spliterator spliterator() {

return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);

}

}

补充:

Java中List集合去除重复数据的方法

1. 循环list中的所有元素然后删除重复

public static List removeDuplicate(List list) {

for ( int i = 0 ; i < list.size() - 1 ; i ++ ) {

for ( int j = list.size() - 1 ; j > i; j -- ) {

if (list.get(j).equals(list.get(i))) {

list.remove(j);

}

}

}

return list;

}

2. 通过HashSet踢除重复元素

public static List removeDuplicate(List list) {

HashSet h = new HashSet(list);

list.clear();

list.addAll(h);

return list;

}

3. 删除ArrayList中重复元素,保持顺序

// 删除ArrayList中重复元素,保持顺序

public static void removeDuplicateWithOrder(List list) {

Set set = new HashSet();

List newList = new ArrayList();

for (Iterator iter = list.iterator(); iter.hasNext();) {

Object element = iter.next();

if (set.add(element))

newList.add(element);

}

list.clear();

list.addAll(newList);

System.out.println( " remove duplicate " + list);

}

4.把list里的对象遍历一遍,用list.contain(),如果不存在就放入到另外一个list集合中

public static List removeDuplicate(List list){

List listTemp = new ArrayList();

for(int i=0;i

if(!listTemp.contains(list.get(i))){

listTemp.add(list.get(i));

}

}

return listTemp;

}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。