【问题标题】:Counting Duplicates and Grouping in an Arraylist计算 Arraylist 中的重复项和分组
【发布时间】:2015-02-04 03:45:34
【问题描述】:

对于我的项目,我们必须使用 Java 处理某些 LISP 措辞。给了其中一项任务:

'(A A A A B C C A A D E E E E)

将重复项分组并输出如下:

′((4A)(1B)(2C)(2A)(1D)(4E))

注意前四个 A 与后两个 A 是如何分开的...

我的问题是跟踪每个字母有多少。我将给定的字母添加到数组列表中,并对其进行了一些操作:

for (int i=0;i<list.size();i++)
    {
        String val=list.get(i);
        String first=list.get(0);
        while (val.equals(first))
        {
            total+=1;
            val="X";
        }
    }

Total 应该是第一次出现的次数,但它一直给我 6。6 是序列中所有 A 的正确数字,但我如何让它停在前四个,记录数字然后继续下一个字母?

【问题讨论】:

  • 因为您使用的是==。比较String值,需要使用equals,如val.equals(first)
  • 字母列表是如何提供的?一个字符串?
  • 逻辑如下:获取第一个字母并从1开始计数器。检查下一个字母是否相同。如果是,则增加计数器并检查下一个。重复直到找到不同的字母。找到后,打印计数器 + 上一个字母,将计数器重置为 1 并重复下一个字母

标签: java string arraylist


【解决方案1】:

这里是 Java 8 Stream API。

 Map<Character, Long> countedDup =  Arrays.asList('A' ,'A' ,'A', 'A', 'B', 'C', 'C', 'A', 'A', 'D', 'E', 'E', 'E', 'E')
        .stream().collect(Collectors.groupingBy(c -> c, Collectors.counting()));
            System.out.println(countedDup);//{A=6, B=1, C=2, D=1, E=4}

【讨论】:

    【解决方案2】:

    这是我的解决方案:

        for (int i = 0; i < list.size(); i++) {
            String first = list.get(i);
            int total = 1;
            while (i + 1 < list.size() && first.equals(list.get(i + 1))) {
                total++;
                i++;
            }
            System.out.println("(" + total + first + ")");
        }
    

    你可以通过调试知道它是如何运行的。

    ***** 请注意,在比较 2 个 String 对象时,切勿使用 ==。使用方法equals()

    【讨论】:

      【解决方案3】:

      这是我的解决方案,虽然没有使用 arrayList:

      已编辑: 根据 Ascalonian

      指出
      String text = "'(A A V A B C C X X X X A A Z Z Z K L N N N N N)";
      int counter = 1;
      System.out.print("'(");
      for (int i = 2; i < text.length() - 1; i = i + 2) {
          System.out.print("(");
          while (((i + 2) < text.length())
              && (text.charAt(i) == text.charAt(i + 2))) {
          ++counter;
          i += 2;
          }
          System.out.print(counter + "" + text.charAt(i) + ")");
          counter = 1;
      }
      System.out.print(")");
      

      o/p 将用于示例文本:

      ((2A)(1V)(1A)(1B)(2C)(4X)(2A)(3Z)(1K)(1L)(5N))

      【讨论】:

      • 您的text 与提供的示例字符串不匹配。它有空格和单引号
      • @Ascalonian 感谢您指出这一点。没看到那个。我的错。
      【解决方案4】:

      不确定是否需要使用ArrayList,但如果不是,我会使用不同的方法,只获取字母,去除空格,将其设为char[] 并迭代每个字母。

      // the initial LISP phrase
      String lispPhrase = "'(A A A A B C C A A D E E E E)";
      
      // Pull out just the letters
      String letters = lispPhrase.substring(2, lispPhrase.length()-1);
      
      // Remove the white space between them
      letters = letters.replaceAll("\\s","");
      
      // Get an array for each letter
      char[] letterArray = letters.toCharArray();
      
      char previousLetter = ' ';
      char nextLetter = ' ';
      int letterCounter = 1;
      
      System.out.print("'(");
      
      // now go through each letter
      for (char currentLetter : letterArray) {
          // If the first time through, set previousLetter
          if (previousLetter == ' ') {
              previousLetter = currentLetter;
          }else {
              nextLetter = currentLetter;
      
              // Is the next letter the same as before?
              if (previousLetter == nextLetter) {
                  letterCounter++;
              }else {
                  // If the next letter is different, print out the previous letter and count
                  System.out.print("(" + letterCounter + previousLetter + ")");
      
                  // Reset the counter back to 1
                  letterCounter = 1;
              }
      
              previousLetter = nextLetter;
          }
      }
      
      System.out.print("(" + letterCounter + previousLetter + "))");  
      

      这给出了以下输出:

      '((4A)(1B)(2C)(2A)(1D)(4E))

      【讨论】:

        【解决方案5】:

        为了获得您在问题中指定的所需输出,我将跟踪给定列表中的当前值和下一个值。元素计数从 1 开始,当相等条件为真时递增,否则重置为 1。只有当相等条件为假时才更新最终输出。

        示例代码:

        编辑我根据@Ascalonian 的建议更新了我的代码。

        String inputString = "'(A A A A B C C A A D E E E E)";
        
        // I assume that the input always starts with "'("
        String finalOutput = inputString.substring(0, 2);
        int valCount = 1;
        
        String valCurrent = inputString.substring(2, 3);
        String valNext = "";
        
        for (int i = 4; i < inputString.length(); i++) {
        
            valNext = inputString.substring(i, i + 1);
            if (valNext.equals(" ")) {
                continue;
            }
        
            if (valCurrent.equals(valNext)) {
                valCount++;
            } else {
                finalOutput += "(" + valCount + valCurrent + ")";
                valCount = 1;
            }
            valCurrent = valNext;
        }
        
        finalOutput += ")";
        
        System.out.println(finalOutput);
        

        输出字符串:'((4A)(1B)(2C)(2A)(1D)(4E))

        我希望这会有所帮助。

        【讨论】:

        • 我实际上并没有阅读您的评论 :)。我只是想解决它,因为我觉得它很有趣。
        • 其实,刚刚注意到这里没有考虑空格和单引号
        • 我实际上假设没有空格并且我没有注意到单引号。我稍后会更新我的答案。但是,OP 没有指定单引号的预期行为。例如,当单引号位于字符串中间时会发生什么?在这种情况下,我只能做出假设。
        • @Ascalonian 感谢您指出我没有注意到的内容。我更新了我的答案。
        • 您的输出缺少 (4E)
        猜你喜欢
        • 2014-04-08
        • 1970-01-01
        • 2021-11-08
        • 2017-01-20
        • 2016-02-15
        • 1970-01-01
        • 2020-12-05
        • 2021-07-06
        • 1970-01-01
        相关资源
        最近更新 更多