0

I have this brainer. I need to iterate over a Map<UUID, List<Items>> groups and return a single value!

Can I do this with Lambda and how? (how do I get the id of the group that has an item of TYPE_12? The item of TYPE_12 is going to be only one across all groups)

Thanks in advance this is my for code:

String theId = null;
for(Map.Entry<UUID, List<Item>> group : groupsOfItems) {
    for (Item item : group.getValue()) {
        if (item.getType() == Types.TYPE_12) {
            theId = group.getKey().toString();
            break;
        }
    }
}
gai-jin
  • 653
  • 2
  • 10
  • 24

3 Answers3

2

If you want to use functional style, you can create a stream from you map entry set, then expand it to get a stream of each item in underlying lists :

Optional<String> result = groupOfItems.entrySet().stream()
            .flatMap(entry -> entry.getValue().stream())
            .filter(item -> Types.TYPE_12.equals(item.getType))
            .map(Item::getId)
            .findAny();

result.ifPresent(id -> System.out.println("A match has been extracted: "+id));

As is, the functional style way is not more performant than the imperative one, but is more easily adaptable. Let's say you want to know if there's more than one match, you can replace findAny by a collector with a limit :

List<String> matchedIds = groupOfItems.entrySet().stream()
            .flatMap(entry -> entry.getValue().stream())
            .filter(item -> Types.TYPE_12.equals(item.getType))
            .map(Item::getId)
            .limit(2)
            .collect(Collectors.toList());

if (matched.isEmpty()) System.out.println("No match found");
else if (matched.size() == 1) System.out.println("Exactly one match found: "+matched.get(0));
else System.out.println("At least two matches exist");

Stream usage also allow parallelization if necessary, by simply adding parallel() step to your pipeline.

amanin
  • 3,436
  • 13
  • 17
  • Thanks! Great! I'll try this out soon! It looks like what I need. I am trying to orient myself towards functional style. – gai-jin Nov 03 '20 at 18:17
1

Here is a solution using lambdas. The difference is this one does not use flatMap and throws an exception if the required value is not found (based on the question stating that there should be one and only one TYPE_12 in the whole value set of the map).

UUID result = groupsOfItems.entrySet().stream()
    .filter(e -> e.getValue().stream()
        .anyMatch(item -> item.getType() == TYPE.TYPE_12))
    .findAny().orElseThrow().getKey();
jrook
  • 3,459
  • 1
  • 16
  • 33
0
String theId = null;

find:
for (Map.Entry<UUID, List<Item>> group : groupsOfItems.entrySet()) {
    for (Item item : group.getValue()) {
        if (item.getType() == Types.TYPE_12) {
            theId = group.getKey().toString();
            break find;
        }
    }
}

No don't use lambda for this. Just use java labels to break out of both for loops after you found your entry. (Notice the find: before the first for loop. That's a label and once you call break find; it will break out of the block marked with that label)

Also you need to use .entrySet in the first for loop. Just passing groupsOfItems won't be enough

IntoVoid
  • 914
  • 4
  • 7