0

I've got two Maps of shops, I'd like to count how many shops of each brand there is in that first Map, but the brands, are available only in second Map. Then I want to sort my results by descending number of shops of each brand. My code looks like this:

Store store, store1, store2, store3, store4, store5, store6;
store = new Store("1", null);
store1 = new Store("2", null);
store2 = new Store("3", null);
Map<String, Store> dynamicShops = new HashMap<>();
dynamicShops.put(store.getId(), store);
dynamicShops.put(store1.getId(), store1);
dynamicShops.put(store2.getId(), store2);

store3 = new Store("1", "ABC");
store4 = new Store("2", "ABC");
store5 = new Store("3", "Abra Cadabra");
store6 = new Store("4", "Abra Cadabra");
Map<String, Store> staticShops = new HashMap<>();
staticShops.put(store3.getId(), store3);
staticShops.put(store4.getId(), store4);
staticShops.put(store5.getId(), store5);
staticShops.put(store6.getId(), store6);

Map<String, Long> stats = dynamicShops.values().stream()
            .collect(groupingBy(s -> staticShops.get(s.getId()).getBrand(), counting()));

Map<String, Long> statsSorted = stats.entrySet().stream()
            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

statsSorted.entrySet().stream().forEach(s -> System.out.println(s.getKey() + " " + s.getValue()));

And produces output I'm expecting:

ABC 2
Abra Cadabra 1

Now I'm wondering is there a way to accompish it in one stream?

Naman
  • 27,789
  • 26
  • 218
  • 353
Krzysztof Tkacz
  • 488
  • 2
  • 5
  • 15
  • 3
    you mean `Map statsSorted = dynamicShops.values().stream() .collect(groupingBy(s -> staticShops.get(s.getId()).getBrand(), counting())) .entrySet().stream() .sorted(Map.Entry.comparingByValue().reversed()) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));` – Youcef LAIDANI Mar 11 '20 at 20:56
  • 1
    @YCF_L, that's technically two streams. ;) – jaco0646 Mar 11 '20 at 20:59
  • 1
    Take a look at https://stackoverflow.com/questions/109383 and do specify what are you trying to achieve with the use of single stream here? – Naman Mar 12 '20 at 04:14
  • @Naman Well I assumed that streaming those values only once not twice, would be just efficient. – Krzysztof Tkacz Mar 12 '20 at 08:59
  • 2
    Efficiency doesn’t depend on how many stream operations you perform. Efficiency depends on what actual operations the CPU has to perform. You can’t sort by a count that isn’t known. In principle, you could implement a data structure that re-sorts on-the-fly whenever counts change, but the performance would be *worse* than counting before sorting. – Holger Mar 13 '20 at 10:11

1 Answers1

2

Here is one solution:

dynamicShops.values()
            .stream()
            .map(s -> staticShops.get(s.getId()).getBrand())
            .collect(Collectors.collectingAndThen(Collectors.groupingBy(Function.identity(), Collectors.counting()), m -> m.entrySet().stream()))
            .sorted(Entry.<String, Long>comparingByValue().reversed())
            .forEach(s -> System.out.println(s.getKey() + " " + s.getValue()));
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • It's still two streams, I guess. I was wondering is there a way to do it somehow in that first collect using some collectingAndThen or something like this. – Krzysztof Tkacz Mar 11 '20 at 21:24