【问题标题】:Algorithm for removing duplicates from ArrayList从 ArrayList 中删除重复项的算法
【发布时间】:2017-05-25 18:59:26
【问题描述】:

我有一个ArrayList<String>,其中包含以下内容:

2#3#1#0

1#0#4#1

9#2#5#0

4#2#3#2

1#1#2#1

输出:6 个不同的数字。

我正在尝试编写一个算法来删除突出显示的数字的重复项,这样我就可以使用计数器来查看所有这些位置总共有多少不同的数字。

我尝试了很多方法,包括以下一些:[Java 使用循环从数组中删除重复项][1]、[Java - 删除 ArrayList 中的重复项][2]、[如何查找重复项中的第一个选项在 Java 数组中?][3] 等等。我至少花了 5 到 10 个小时试图弄清楚我做错了什么,但我做不到,所以我求助于你。

大多数时候,我在网上找到的解决方案似乎都适用于简单的东西,但对我来说却不是。其中,当我尝试打印不同的字符时,它总是返回错误的int 数字。

我也试过,也试过把每一行数字分成不同的int Array[],然后比较,但它不会捕捉到所有不同的值。

在另一个例子中,我总共有 5 个不同的数字,结果我一直得到“4 个不同”,所以我什至尝试了 long n = ArrayList.stream().distinct().count(); 只是为了看看我是否做错了什么,但即使这个东西也返回了“4 个不同”的数字。

我知道最简单的方法是使用SetMap,但我不想那样做。我想要一个算法。

编辑:

我尝试过的许多事情之一如下:

for (int m = 0; m < (size-1); m++){
        for (int j = m + 1; j < size; j++){
            if (ArrayList.get(j).charAt(0) != ArrayList.get(m).charAt(0)){
                continue;
            }
            current++;
            ArrayList.remove(j).charAt(0);
            j--;
            size--;
        }
    }

有了这个,我必须用另一个ArrayList.get().charAt(4)

EDIT2:

我在 [here][1] 找到了以下代码,但在这种情况下如何实现呢?

public static <T> ArrayList<T> uniquefy(ArrayList<T> myList) {

    ArrayList <T> uniqueArrayList = new ArrayList<T>();
    for (int i = 0; i < myList.size(); i++){
        if (!uniqueArrayList.contains(myList.get(i))){
            uniqueArrayList.add(myList.get(i));
        }
    }

    return uniqueArrayList;
}

编辑3: 我找到了一个可能的解决方案,但它给了我一个 IndexOutOfBoundsException。 我已将数字 2, 1, 9, 4, 1 放入 Array11, 4, 5, 3, 2 放入 Array2,但是当我尝试比较它们,我得到了提到的错误。

boolean stopSequence = false;
    for (int i = 0; i < Array1.length; i++){
        for (int a = 0; a < Array2.length && !stopSequence;){
            if (Array1[i] != Array2[a]){
                Array1[i] = 0;
                a++;
            }
            if (Array1[i] == Array2[a]){
                Array1[i] = 0;
                stopSequence = true;
            }
        }
        stopSequence = false;
    }

[1]: https://stackoverflow.com/questions/26998156/java-remove-duplicates-from-array-using-loops
[2]: https://stackoverflow.com/questions/2435156/java-removing-duplicates-in-an-arraylist
[3]: http://javarevisited.blogspot.com.es/2015/06/3-ways-to-find-duplicate-elements-in-array-java.html
[4]: https://stackoverflo

w.com/questions/203984/how-do-i-remove-repeated-elements-from-arraylist?rq=1

【问题讨论】:

  • 给定输入示例所需的结果是什么?
  • 我会使用计数器并打印,在这种情况下,“6 个不同的数字”。
  • 当您的代码不工作时...在此处显示。见minimal reproducible example
  • 您的问题到底是什么?我们不会为您编写代码,您也没有发布任何代码。您还拒绝将所有数字放在一组中,然后打印该组的大小的明显解决方案。为什么?
  • @GhostCat 好的。我将提出我尝试过的“解决方案”之一。

标签: java arrays arraylist duplicates


【解决方案1】:

算法比你想象的要简单得多:

  1. 将每个字符串转换成一对字符
  2. 将所有字符放入删除重复项的集合或流中
  3. 统计字符数。

这是一个完整的例子:

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

public class Duplicates {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("2#3#1#0",
                                          "1#0#4#1",
                                          "9#2#5#0",
                                          "4#2#3#2",
                                          "1#1#2#1");
        System.out.println(
            list.stream()
                .flatMapToInt(s -> IntStream.of(s.charAt(0), s.charAt(4)))
                .distinct()
                .count());
    }
}

编辑:您似乎想遵守荒谬的限制,因此既不使用 Stream 也不使用 Set,这些都是完全有意义的。这里的代码只使用了列表,但做的事情与上面基本相同,但效率要低得多:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Duplicates {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("2#3#1#0",
                                          "1#0#4#1",
                                          "9#2#5#0",
                                          "4#2#3#2",
                                          "1#1#2#1");
        List<Character> uniqueChars = new ArrayList<>();
        for (String s : list) {
            Character c0 = s.charAt(0);
            Character c4 = s.charAt(4);

            if (!uniqueChars.contains(c0)) {
                uniqueChars.add(c0);
            }
            if (!uniqueChars.contains(c4)) {
                uniqueChars.add(c4);
            }
        }

        System.out.println(uniqueChars.size());
    }
}

【讨论】:

  • 很遗憾,我不能使用Stream。我很确定这一切都可以使用普通循环来完成,因为我做过类似的事情,而不是当我在每个字符串行中有 2 件事情需要单独与其他所有事情进行比较时。
  • 优秀的解决方案!流只是不停地让我震惊。 +1
  • 我在想一个类似的解决方案,但是 flatMapToInt 是一种非常好的紧凑的编写方式。
  • @DoombringerBG 您可以使用循环和 Set 应用相同的算法。但除非你受到平台(android?)的限制,否则你最好开始学习流,因为它们非常强大,并且允许编写简洁、富有表现力和高效的代码。
  • @JBNizet 如果我想在这种情况下使用 Sets 或 Maps 或 Streams 或 w/e,我不会问我问了什么。
【解决方案2】:

计算高亮位置的不同数量并不难。您可以使用称为频率数组的辅助数组来获得预期的结果。

使用频率数组尝试这个简单的算法,我认为它非常适合您的情况:

       ArrayList<String> numlist=new ArrayList<String>();
       int freq[] = new int [10];
       numlist.add("2#3#1#0");
       numlist.add("1#0#4#1");
       numlist.add("9#2#5#0");
       numlist.add("4#2#3#2");
       numlist.add("1#1#2#1");
       for(int i = 0; i < numlist.size(); i++){
           String row = numlist.get(i);          
           int numValue1 = Character.getNumericValue(row.charAt(0));
           int numValue2 = Character.getNumericValue(row.charAt(4));
           freq[numValue1]++;
           freq[numValue2]++;          
       }
       int count = 0;
       for(int i = 0; i < 10; i++){
           if(freq[i] > 0){
               count++;
           }
       }
       System.out.println(count + " different numbers");

输出

6 different numbers

【讨论】:

  • 有点太晚了,但我想我会用这个,如果 JB Nizet 没有打败你。不管怎样,我很感谢你的帮助。 :3
  • 没问题。别客气。不要让你的问题更复杂,尽量简单。尝试将其分解为更简单的部分,以便以干净的方式获得预期的结果。
【解决方案3】:

另一个带有位掩码的选项:

public static void main(String[] args) {
    List<String> arrayList = Arrays.asList("2#3#1#0", "1#0#4#1", "9#2#5#0", "4#2#3#2", "1#1#2#1");
    int mask = 0;
    for(String s : arrayList) { // Place the bits
        mask = mask | (1 << Character.getNumericValue(s.charAt(0))) | (1 << Character.getNumericValue(s.charAt(4)));
    }
    int counter = 0;
    for(int i = 0; i < 32; i++) { // count the bits
        counter += (mask & (1 << i)) == 1 << i ? 1 : 0;
    }
    System.out.println(counter);
}

输出:

6

这依赖于代码执行结束时的位掩码:

1000111110

这可能比大多数解决方案更快,因为它不依赖于传统的数据结构。

【讨论】:

  • 在我的生活中从未见过位掩码,但它似乎很容易阅读。 :3
  • 对于看到这个的人来说只是一个问题:有没有一种潜在的方法可以为这个问题提供一个“更快”的解决方案,它使用更少的内存?与上面显示的其他解决方案相比,这在效率方面如何?
【解决方案4】:

嗯,一个好的做法总是将问题分成更小的部分

例如,一个好的设计应该是一个包含这些成员的类:

  • digits:这是整数数组的实例变量,包含每个数字重复的次数。它必须预先设置为允许的最大数字(我猜是 9)。
  • differentDigits: 是一个包含不同位数的实例变量。
  • processList:此方法应接收列表以浏览它并为每个项目调用processItem
  • processItem:该方法需要接收一个item String,并按照指定的格式解析数字(例如通过StringTokenizer),并为每个需要的数字调用storeDigit
  • storeDigit:此方法应接收一个 int 并使用它来索引实例数组 digits,并增加索引位置。如果索引位置为 0,它也应该增加 differentDigits

【讨论】:

    猜你喜欢
    • 2018-05-29
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多