Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reduce multiple arrays to a list

I'm trying to filter and reduce a List<Map<String, Object>> to List<String> with Java8 new lambdas by doing this:

List<Map<String, Object>> myObjects = new ArrayList<>();
myObjects.stream()
    .filter(myObject-> myObject.get("some integer value").equals(expectedValue))
    // myObject.get("some attribute") == ["some string", "maybe another string"]
    .map(myObject-> myObject.get("some attribute"))
    .collect(Collectors.toList());

The result is a List but I want to combine all the Strings inside the array to the resulting List<String>.

To clarify it, this is the result I'm getting now:

ArrayList{["some string"], ["another string"]}

But I want this:

ArrayList{"some string", "another string"}

Can someone give me a hint in which part I have to reduce the String[] to a String? I'd guess its on the .map() part but I don't know what I shall change there.

edit:

That's how the List<Map<String, Object>> myObjects can be generated for testing purpose:

List<Map<String, Object>> myObjects = new ArrayList<>();
Map<String, Object> myObject = new HashMap<>();
myObject.put("some integer value", 1);
String[] theStringIWant = new String[1];
theStringIWant[0] = "Some important information I want";
myObject.put("some attribute", theStringIWant);
myObjects.add(myObject);

Which looks like this:

List<MyObject{"some attribute": 1}>

Note: That's just an example from my unittest. The list normaly contains more than one element and every map has more attributs and not just some attribute.

like image 261
Peter Avatar asked Oct 13 '17 13:10

Peter


2 Answers

You might need to have another filter, but this is how I'd make it:

public static void main(String[] args) {
    List<Map<String, Object>> myObjects = new ArrayList<>();
    Map<String, Object> myObject1 = new HashMap<>();

    myObject1.put("some attribute", 1);
    myObject1.put("some string", new String[] { "Some important information I want"});
    myObjects.add(myObject1);

    Map<String, Object> myObject2 = new HashMap<>();
    myObject2.put("some attribute", 1);
    myObject2.put("some string", new String[] { "hello", "world" });
    myObjects.add(myObject2);

    Map<String, Object> myObject3 = new HashMap<>();
    myObject3.put("some attribute", 2);
    myObject3.put("some string", new String[] { "don't", "want", "this"});
    myObjects.add(myObject3);

    Map<String, Object> myObject4 = new HashMap<>();
    myObject4.put("some string", new String[] { "this", "one", "does", "not", "have", "some attribute"});
    myObjects.add(myObject4);

    List<String> list = myObjects.stream()
            .filter(map -> map.containsKey("some attribute"))
            .filter(map -> map.get("some attribute").equals(Integer.valueOf(1)))
            .flatMap(map -> Arrays.stream((String[])map.get("some string")))
            .collect(Collectors.toList());

        System.out.println(list);
    }

The result is [Some important information I want, hello, world]

like image 53
M. le Rutte Avatar answered Nov 07 '22 22:11

M. le Rutte


You should be able to obtain that with the flatMap method with returning a Stream of the String[] instead of the map method:

myObjects.stream()
    .filter(myObject-> myObject.get("some integer value").equals(expectedValue))
    .flatMap(myObject-> Arrays.stream((String[])map.get("some attribute")))
    .collect(Collectors.toList());

But be aware that if Arrays.stream((String[])map.get("some attribute")) throws an Exception, e.g. if map.get("some attribute") is not a String[], then it would be swallowed by the Stream.

like image 45
user1983983 Avatar answered Nov 07 '22 22:11

user1983983