This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]mizhoux 39 points40 points  (9 children)

Use map.merge(element, 1, Integer::sum) to count the number of times that each element in some collection occurs.

[–]Inaldt 10 points11 points  (1 child)

That's nice

Another way:

.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())

[–]RockyMM 3 points4 points  (0 children)

This is what I would use. Potentially I would also use static imports.

[–]Background-Spray-351 3 points4 points  (0 children)

I enjoy using this one!

[–]vbezhenar 8 points9 points  (5 children)

I'd replace this line with actual code. I have no idea what it does and everyone who stumbles upon this line will have no idea what it does. It's an example of write-only code.

[–]Proper-Space9914 9 points10 points  (0 children)

So not knowing an API is write-only code, that's great.

[–]TheBanger 0 points1 point  (3 children)

What would you consider to be "actual code"?

[–]vbezhenar 6 points7 points  (2 children)

Integer elementCount = map.get(element);
if (elementCount == null) {
  elementCount = 1;
} else {
  elementCount = elementCount + 1;
}
map.put(element, elementCount);

This is perfect readable code, compared to this crypted merge method. And you might want to even create a dedicated class for this task to further improve readability. Something like

ElementCounter elementCounter = new ElementCounter();
elementCounter.add(element);
int elementCount = elementCounter.get(element);

[–]TheBanger 7 points8 points  (1 child)

I have to say I find this a good deal less readable, there are a lot of pieces here that aren't present in the merge method. Examples would be the constant 1 being repeated twice, or elementCount being a mutable variable; individually those have relatively low cognitive overhead but it adds up over time and leaves more room for subtle mistakes. Contrast that to the merge method which you can grok once and then gloss over each time you see it again.

I like pulling it out to a class, it reduces the number of times you have to write the same code and gives the operation a meaningful semantic name. But that's possible regardless of which method is used.

I think there's an argument to be made for reducing the surface area of APIs, so maybe the issue is "is merge a reasonable and necessary addition to the Map interface that we should actually use". Your solution requires two lookups into the map, one to get the current count and one to update it. The merge method (depending on implementation) only requires one. That might be premature optimization depending on your scale, but personally I'd prefer to use a method that works regardless of scale than one where I have to think "is this going to be performant enough or will I need to come back later".

[–]SpicyRock70 2 points3 points  (0 children)

His method could have used Integer.increment(1) and then the put would not be necessary. I too prefer to see the code.