【问题标题】:Find matching string occurrence in an ArrayList<String>在 ArrayList<String> 中查找匹配的字符串
【发布时间】:2015-07-14 12:05:12
【问题描述】:

我有一个ArrayList&lt;String&gt;,其中包含以字符串形式表示的日期,格式为yyyy-MM-dd,例如:

ArrayList<String> dates = new ArrayList<>(); 
dates.add("1991-02-28");
dates.add("1991-02-28");
dates.add("1994-02-21");

我想知道相同String(日期)出现在列表中的次数。在上面的示例中,我想实现以下输出:

1991-02-28, 2
1994-02-21, 1

我试过下面的代码

    ArrayList<String> dates = new ArrayList<>();
    dates.add("1991-02-28");
    dates.add("1991-02-28");
    dates.add("1994-02-21");
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
    HashMap<String, String> dateCount = new HashMap<String, String>();

    String first = dates.get(0);
    int count = 1;
    dateCount.put(first, String.valueOf(count));
    for (int i = 1; i < dates.size(); i++) {
        if (first.equals(dates.get(i))) {
            count++;
        } else {
            first = dates.get(i);
            dateCount.put(dates.get(i), String.valueOf(count));
            count = 0;
        }
    }
    for (String date : dates) {
        String occ = dateCount.get(date);
        System.out.println(date + ", " + occ);
    }

但它会打印出来

1991-02-28, 1
1991-02-28, 1
1994-02-21, 2

我累了,卡住了,最后求助于 SO。任何帮助表示赞赏。

【问题讨论】:

  • 我的问题可能表述得很糟糕。我想打印的是1991-02-28, 21994-02-21, 1 @AmirAfghani
  • 我现在看到你的编辑了。所以,实际上这是一个 groupBy 操作。您使用的是 Java 8 吗? Guava 也有一个方法可以为你做到这一点..
  • 准确地说,groupBy 会解决它。不幸的是,我目前正在使用 Java 7。@AmirAfghani

标签: java string arraylist


【解决方案1】:

我可能遗漏了一些东西,但看起来你可以做一些简单的事情,只需在 HashMap 中保留 Dates 的计数,然后迭代 HashMap 以获取输出:

    ArrayList<String> dates = new ArrayList<>();
    dates.add("1991-02-28");
    dates.add("1991-02-28");
    dates.add("1994-02-21");
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
    HashMap<String, Integer> dateCount = new HashMap<String, Integer>();

    for (int i = 0; i < dates.size(); i++) {

        String date = dates.get(i);
        Integer count = dateCount.get(date);
        if (count == null){
          dateCount.put(date, 1);
        }
        else{
          dateCount.put(date, count + 1);
        }

    }
    for(String key : dateCount.keySet()){
        Integer occ = dateCount.get(key);
        System.out.println(key + ", " + occ);
    }

输出:

1991-02-28, 2
1994-02-21, 1

【讨论】:

  • 你没有错过任何东西——我做了同样的事情,得到了同样的结果。 this 或 api 是正确的答案。
【解决方案2】:

我还没有调试你的逻辑,但是你可以使用 Google Guava 的 index 方法来执行 groupBy。

【讨论】:

    【解决方案3】:

    这是正确的解决方案:

    公共类主类 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
    
        ArrayList<String> dates = new ArrayList<>();
        dates.add("1991-02-28");
        dates.add("1991-02-28");
        dates.add("1994-02-21");
        //SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        HashMap<String, Integer> dateCount = new HashMap<String, Integer>();
    
        //          String first = dates.get(0);
        //          int count = 1;
        //          dateCount.put(first, String.valueOf(count));
        //          for (int i = 1; i < dates.size(); i++) {
        //              if (first.equals(dates.get(i))) {
        //                  count++;
        //              } else {
        //                  first = dates.get(i);
        //                  dateCount.put(dates.get(i), String.valueOf(count));
        //                  count = 0;
        //              }
        //          }
    
        for(int i= 0; i < dates.size();i++) 
        {
            if(dateCount.containsKey(dates.get(i)))
            {
                dateCount.put(dates.get(i),dateCount.get(dates.get(i))+1); 
            }
            else 
                dateCount.put(dates.get(i),1); 
        }
        for (String date : dates) {
            int occ = dateCount.get(date);
            System.out.println(date + ", " + occ);
        }
    
    }
    

    }

    但是,您需要遍历 hashmap 而不是 ArrayList 才能获得所需的输出..

    希望这有帮助!

    【讨论】:

      【解决方案4】:

      您所描述的数据结构通常称为 Multiset 或 Bag(通常使用 Integer 作为值,而不是 String)。

      Guava 提供了一个非常漂亮的Multiset 接口,这使得这个操作变得很简单:

      Multiset<String> counts = HashMultiset.create();
      for(String date : dates) {
        counts.add(date);
      }
      System.out.println(counts);
      
      [1991-02-28 x 2, 1994-02-21]
      

      即使没有 Guava,您也可以使用 Map&lt;T, Integer&gt; 和一些样板来伪造 Multiset:

      Map<String, Integer> counts = new HashMap<>();
      for(String date : dates) {
        Integer count = counts.get(date);
        if(count == null) {
          count = 0;
        }
        counts.put(date, count+1);
      }
      System.out.println(counts);
      
      {1991-02-28=2, 1994-02-21=1}
      

      【讨论】:

        【解决方案5】:

        如果只需要计算List&lt;String&gt; 集合中每个full 字符串的出现次数,那么Java 7(或更早版本)中有许多简单的方法可以做它 - 不一定是最快的,但可以工作。

        例如,可以从列表中创建一个Set 并遍历集合中的所有项目,调用Collections.frequency(list, item),其中listList&lt;String&gt; 集合,item 是集合的每个字符串迭代。

        这是一个简单的实现:

          public static class FrequencyCount {
            public static void main(String[] args){
              java.util.ArrayList<String> dates = new java.util.ArrayList<>();
              dates.add("1991-02-28");
              dates.add("1991-02-28");
              dates.add("1994-02-21");
              java.util.Set<String> uniqueDates = new java.util.HashSet<String>(dates);
              for (String date : uniqueDates) {
                System.out.println(date + ", " + java.util.Collections.frequency(dates, date));
              }
            }
          }
        

        输出:

        1994-02-21, 1
        1991-02-28, 2
        

        【讨论】:

        • 这是一个非常干净的解决方案,按预期工作,谢谢。
        • Collections.frequency() 是一个 O(n) 操作,这意味着这个解决方案是 O(n^2)。每个其他答案都包含一个 O(n) 解决方案;这不是你想怎么做。
        • 当然。我还建议像您这样的基于地图的解决方案作为更好的选择。这是演示工作结果的最简单方法,而且问题似乎不是大规模的,也不需要高性能,因此我更喜欢最简单的方法。顺便说一句,从昨天开始我已经给你+1了。 :-)
        • 我不太确定我是否跟随。您能否详细说明为什么这个答案不如其他答案?我使用 TreeSet 而不是 HashSet,如果这改变了任何东西:-) @ dimo414
        • @Marcus TreeSetHashSet 无关(尽管 TreeSet 在大多数操作中是 O(log n),因此通常比 HashSet 更糟)。这里的问题是Collections.frequency() 被称为n 次,并且每次都必须遍历整个dates 列表才能计算每个元素。那是 O(n^2) 时间。使用 MultisetMap&lt;T, Integer&gt; 将在 O(n) 时间内完成相同的工作。
        猜你喜欢
        • 2011-03-08
        • 1970-01-01
        • 1970-01-01
        • 2011-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多