2

I am using Java8 to achieve the below things,

 Map<String, String> m0 = new HashMap<>();
        m0.put("x", "123");
        m0.put("y", "456");
        m0.put("z", "789");

        Map<String, String> m1 = new HashMap<>();
        m1.put("x", "000");
        m1.put("y", "111");
        m1.put("z", "222");

        List<Map<String, String>> l = new ArrayList<>(Arrays.asList(m0, m1));

        List<String> desiredKeys = Lists.newArrayList("x");

        List<Map<String, String>> transformed = l.stream().map(map -> map.entrySet().stream()
                .filter(e -> desiredKeys.stream().anyMatch(k -> k.equals(e.getKey())))
                .collect(Collectors.toMap(e -> e.getKey(), p -> p.getValue())))
                .filter(m -> !m.isEmpty())
                .collect(Collectors.toList());
        System.err.println(l);
        System.err.println(transformed);
        List<String> values = new ArrayList<>();
        for (Map<String,String> map : transformed) {
            values.add(map.values().toString());
            System.out.println("Values inside map::"+map.values());
        }
        System.out.println("values::"+values); //values::[[123], [000]]

Here, I would like to fetch only the x-values from the list. I have achieved it but it is not in a proper format.

Expected output: values::[123, 000]

Actual output: values::[[123], [000]]

I know how to fix the actual output. But is there any easy way to achieve this issue? Any help would be appreciable.

3 Answers 3

5

You do not need to iterate over the entire map to find an entry by its key. That's what Map.get is for. To flatten the list of list of values, use flatMap:

import static java.util.stream.Collectors.toList;
.....

List<String> values = l.stream()
    .flatMap(x -> desiredKeys.stream()
            .filter(x::containsKey)
            .map(x::get)
    ).collect(toList());

On a side note, avoid using l (lower case L) as a variable name. It looks too much like the number 1.

Sign up to request clarification or add additional context in comments.

7 Comments

is it possible fetch "y" value based on "x" key?
@VelNaga can you clarify that? What do you want the output to be?
If the X-value is present in the map then return Y-value.For ex) take 1st map, I will check for "x" value "123" if it is present then return Y value "456"
So if the map contains both key "x" and key "y" you want to return the value for key "y"?
Yep based on x-value
|
3

I’m not sure Streams will help, here. It’s easier to just loop through the Maps:

Collection<String> values = new ArrayList<>();

for (Map<String, String> map : l) {
    Map<String, String> copy = new HashMap<>(map);
    copy.keySet().retainAll(desiredKeys);
    values.addAll(copy.values());
}

6 Comments

Alone the usage of both views makes this more elegant than streams, would upvote if I had some left :)
It might be expensive to copy the entire map first, if the number of desired keys is significantly smaller than the original map sizes. Your solution has a point if the source maps are mutable and their original content is not required, so that no copy is required.
@Holger Copying the entire Map means copying only references to the keys and values. It’s not a lot of memory usage, relatively speaking, even for large Maps.
Unfortunately, it’s not that simple. HashMap does not only create an array under the hood, but an Entry instance for every mapping. Still, I was actually focusing on the CPU expenses, as HashMap has no cheap way of transferring mappings, even if the source is already an instance of HashMap. So copying an entire map implies hashing all entries, as opposed to looking up each desired key only.
is it possible fetch "y" value based on "x" key?
|
3

Flat map over the stream of maps to get a single stream representing the map entries of all your input maps. From there, you can filter out each entry whose key is not contained in the desired keys. Finally, extract the equivalent value of each entry to collect them into a list.

final List<String> desiredValues = l.stream()
    .map(Map::entrySet)
    .flatMap(Collection::stream)
    .filter(entry -> desiredKeys.contains(entry.getKey()))
    .map(Map.Entry::getValue)
    .collect(Collectors.toList());

EDIT

This assumes that if a map has the key "x" it must also has the key "y" so to fetch the corredponding value.

final List<String> desiredValues = l.stream()
    .filter(map -> map.containsKey("x"))
    .map(map -> map.get("y"))
    .collect(Collectors.toList());

4 Comments

is it possible fetch "y" value based on "x" key?
@VelNaga do you mean fetch entries whose key is "x" and value is "y" ?
If the map has the value "x" then fetch value of "Y"
If the X-value is present in the map then return Y-value.For ex) take 1st map, I will check for "x" value "123" if it is present then return Y value "456"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.