在不改变元素顺序的情况下,从数组中移除重复项

24
我有一个数组,比如说 List<Integer>,内容如下:139, 127, 127, 139, 130 如何去重并保持其原始顺序?即得到:139, 127, 130

手动删除重复项,在这种情况下,您可以保留顺序。 - user2173738
12个回答

32

1
嗯...那是一个降级,我正在使用Java 7的钻石符号。 - Paul Vargas
5
抱歉,喝完咖啡后我会变成完全不同的人。 - Maroun

10

去掉 LinkedHashSet 开销 (使用仅稍微更快的 HashSet 来表示已经查找过的元素):

List<Integer> noDuplicates = list
        .stream()
        .distinct()
        .collect(Collectors.toList());

请注意,Stream.distinct() 合同保证了顺序:
对于有序的流,选择不同的元素是稳定的(对于重复的元素,保留出现在遇到顺序中的第一个元素)。

7

使用这个一行代码:

yourList = new ArrayList<Integer>(new LinkedHashSet<Integer>(yourList))

2

从您的列表中构建一个Set - "一个不包含重复元素的集合":

Set<Integer> yourSet = new HashSet<Integer>(yourList);

并将其转换回您想要的任何格式。

注意:如果您想保留顺序,请使用LinkedHashSet


1
HashSet是否保留插入顺序? - Marco Forberg
2
你必须使用 LinkedHashSet 来保留插入顺序。 - Axel
1
你需要一个 LinkedHashSet。 - Andreas
1
这不保留顺序 afak - user1156544

0

方法一:在Python中 => 使用集合和列表推导式

a= [139, 127, 127, 139, 130]

print(a)
seen =set()
aa = [ch  for ch in a if ch not in seen and not seen.add(ch)]
print(aa)

方法二:

aa = list(set(a))
print(aa)

在Java中:使用Set并创建一个新的ArrayList。
class t1 {
    public static void main(String[] args) {

int[] a = {139, 127, 127, 139, 130};
List<Integer> list1 = new ArrayList<>();

Set<Integer> set = new LinkedHashSet<Integer>();
for( int ch  : a) {
    if(!set.contains(ch)) {
        set.add(ch);
    }


}//for
set.forEach( (k) -> list1.add(k));
System.out.println(list1);

}
    }

0
Bro this is you answer but this have 0(n2) T.C remember.

vector<int> sol(int arr[],int n){
vector<int> dummy;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
    if(arr[i]==arr[j]){
        dummy.push_back(j);
    }
   }
 }
 vector<int> ans;
 for(int i=0;i<n;i++){
 bool check=true;
  for(int j=0;j<dummy.size();j++){
    if(dummy[j]==i){
        check=false;
    }
 }
 if(check==false)
   continue;
  ans.push_back(arr[i]);
  }
  return ans;
  }

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

尽管将ArrayList转换为HashSet可以有效地去除重复项,但如果您需要保留插入顺序,我建议您使用这个变体

// list是一些字符串列表

   Set<String> s = new LinkedHashSet<String>(list);

然后,如果您需要获取回List引用,可以再次使用转换构造函数。

0

有两种方法:

  1. 创建只包含唯一整数的新列表

    • (与Maroun Maroun的答案相同)
    • 您可以使用2个嵌套的for循环来执行此操作,如下所示O(n.n/2):

      List<int> src,dst;
      // src是输入列表
      // dst是输出列表
      dst.allocate(src.num); // 准备大小以避免通过重新分配减速
      dst.num=0;             // 从空列表开始
      for (int i=0;i<src.num;i++)
       {
       int e=1;
       for (int j=0;i<dst.num;i++)
        if (src[i]==dst[j]) { e=0; break; }
       if (e) dst.add(src[i]);
       }
      
  2. 您可以选择重复项并将其删除... O(2.n)使用标记删除

    • 这样会快得多,但您需要整个int范围的内存表
    • 如果您使用数字<0,10000>,则需要BYTE cnt[10001]
    • 如果您使用数字<-10000,10000>,则需要BYTE cnt[20002]
    • 对于这样的小范围来说还可以,但如果您必须使用32位范围,则需要4GB !!!
    • 通过位打包,您可以每个值有2位,因此仅需1GB,但对我来说仍然太多了
    • 好的,现在如何检查重复性...

      List<WORD> src;  // src是输入列表
      BYTE cnt[65536]; // 计算所有使用数字的使用情况
      int i;
      for (i=0;i<65536;i++) cnt[i]=0; // 清除所有数字的计数
      for (i=0;i<src.num;i++)         // 计算列表中使用数字的计数  
       if (cnt[src[i]]!=255) 
        cnt[src[i]]++;
      
    • 此后,任何数字i都是重复的,如果(cnt[i]>1)
    • 所以现在我们想要删除重复项(除了一个之外的所有项)
    • 为此,请将cnt[]更改如下

      for (i=0;i<65536;i++) if (cnt[i]>1) cnt[i]=1; else cnt[i]=0;
      
    • 好的,现在来到删除部分:

      for (i=0;i<src.num;i++)         
       if (cnt[src[i]]==1) cnt[src[i]]=2; // 第一次不要删除
        else if (cnt[src[i]]==2)          // 但所有其他人都是
         { 
         src.del(i);
         i--;                             // 删除后,src中的索引已更改,因此请重新检查相同的索引
         }
      
  3. 您可以将两种方法结合在一起

  4. 从列表中删除项目很慢,因为列表中的项目移位
    • 但是可以通过向项目添加删除标志来加速
    • 而不是删除,只需设置标志
    • 并且在所有要删除的项目都被标记后,只需一次性删除它们O(n)

PS. 抱歉使用了非标准的列表,但我认为代码足够易懂,如果不是,请评论我并回复。

PPS. 对于带符号值的使用,请不要忘记将地址向半范围移动!!!


0
使用LinkedHashSet来去除重复项并保持顺序。

0

我理解你需要保留插入顺序,除了使用 @Maroun Maroun 提到的 set 外,你可以使用特殊实现,例如 LinkedHashSet<E>,它恰好可以满足你的需求。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接