【问题标题】:Is there a more efficient way to make HashMap with a counter from an ArrayList?有没有更有效的方法来使用 ArrayList 中的计数器制作 HashMap?
【发布时间】:2018-11-07 01:01:01
【问题描述】:

我有一个方法允许我从ArrayList 创建一个HashMap,方法是获取AirbnbListing 对象,然后将邻居名称与HashMap 中的任何键进行比较。如果它还没有在 hashmap 中,我会添加一个从 1 开始的计数器,如果它已经存在,我会增加计数器。

这里有没有更有效的方法是我的代码:

    public HashMap<String, Integer> sortHousesInNbrhood(ArrayList<AirbnbListing> priceRangeListing) {
    HashMap<String, Integer> housesInNbrhood = new HashMap<>();
    for (AirbnbListing listing : priceRangeListing) {
        if (housesInNbrhood.isEmpty()) {
            housesInNbrhood.put(listing.getNeighbourhood(), 1); 
        } else if (housesInNbrhood.containsKey(listing.getNeighbourhood())) {
            housesInNbrhood.replace(listing.getNeighbourhood(), housesInNbrhood.get(listing.getNeighbourhood()) + 1);
        } else {
            housesInNbrhood.put(listing.getNeighbourhood(),1); 
        }
    }

    return housesInNbrhood;
}

【问题讨论】:

  • 这里的问题是,什么对你来说“更有效率”?更快的执行时间?少量编译的字节码?有很多指标可以用来衡量效率。
  • 由于当今的服务器资源非常丰富,请考虑多一些代码以提高可读性(可读性更高)。因为让开发人员(包括几个月后的您自己)想知道代码的作用是低效的,因为您太努力地将其精简为“聪明的”缩短。
  • 啊,我会修改我的问题,最好是更快的执行时间。
  • 这就是我的意思。如果它更具可读性,那就这样做,如果它是相同的并且更少的代码就这样做。如果它的可读性较差,请不要这样做,因为与可能导致开发时间不得不找出原本完全可以的东西相比,您在执行时间上节省的纳秒是微不足道的 :)
  • 有不同的选项来解决这个问题,它们在可读性上没有太大差异,但在性能上可能会有显着的差异。我在stackoverflow.com/a/29127257/3182664 中对一个非常相似的案例的不同选项进行了比较

标签: java sorting arraylist hashmap counter


【解决方案1】:

使用groupingBy 收集器和counting 作为下游收集器:

priceRangeListing.stream()
                 .collect(groupingBy(AirbnbListing::getNeighbourhood, counting()));

注意,上面会产生一个Map&lt;String, Long&gt;,但如果你真的想要Map&lt;String, Integer&gt;,那么使用summingInt收集器作为下游:

priceRangeListing.stream()
       .collect(groupingBy(AirbnbListing::getNeighbourhood, summingInt(e -> 1)));

【讨论】:

  • 当它“收集”时我怎么知道它被收集到地图中?
  • @LogiGunaratnam groupingBy 返回Map&lt;AirbnbListing, Long&gt;
  • @LogiGunaratnam Lino 所说的是正确的。只是为了扩展 groupingBy 将始终返回一个地图,但要决定将结果收集到哪种类型的地图中,您需要使用 groupingBy 的不同变体,例如priceRangeListing.stream() .collect(groupingBy(AirbnbListing::getNeighbourhood, HashMap::new, counting()));
  • @Lino minor 但我确定您的意思是 Map&lt;String, Long&gt; 而不是 Map&lt;AirbnbListing, Long&gt;
  • 值得一提的是,您需要import static java.util.stream.Collectors.*; 才能编译此代码。
【解决方案2】:
public HashMap<String, Integer> sortHousesInNbrhood(ArrayList<AirbnbListing> priceRangeListing) {
    HashMap<String, Integer> housesInNbrhood = new HashMap<>();
    for (AirbnbListing listing : priceRangeListing) {
         housesInNbrhood.compute(listing.getNeighbourhood(), (k, v) -> (v == null) ? 1 : v + 1);
    }

    return housesInNbrhood;
}

【讨论】:

    【解决方案3】:

    Multiset 是专门用于跟踪对象在集合中出现的次数的数据结构。它们非常适合您的问题!

    它们在 Java 标准库中不可用,但它们在 Guava 库中。

    我建议您将HashMap 作为您方法的返回值替换为Multiset。那样的话,读者会更清楚它包含的内容。

    使用该解决方案,代码如下所示:

    public Multiset<String> sortHousesInNbrhood(List<AirbnbListing> priceRangeListing) {
        Multiset<String> housesInNbrhood = TreeMultiset.create();
        // Multimap automatically counts the number of times an object have been added
        priceRangeListing.forEach(list -> housesInNbrhood.add(list.getNeighbourhood()));
        return housesInNbrhood;
    }
    
    // Use the multiset like this:
    public void useMultiset(List<AirbnbListing> priceRangeListing) {
        Multiset<String> s = sortHousesInNbrhood(priceRangeListing);
        System.out.println("Houses in Bagdad:" + s.count("Bagdad"));
    
        System.out.println("All counts: ");
        for (Entry<String> e : s.entrySet()) {
            System.out.println(e.getElement() + ": " + e.getCount());
        }
    }
    

    如果您必须返回 HashMap,那么您可以像这样从 Multiset 构造它:

    public Map<String, Integer> sortHousesInNbrhood_2(List<AirbnbListing> priceRangeListing) {
        Multiset<String> housesInNbrhood = TreeMultiset.create();
        priceRangeListing.forEach(list -> housesInNbrhood.add(list.getNeighbourhood()));
        return housesInNbrhood.entrySet().stream().collect(toMap(Entry::getElement, Entry::getCount));
    }
    

    多重集和多重映射是我最喜欢的一些数据结构。太方便了!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多