Flatten lists in map into single list

I have defined a map like below and it has lists of strings as values

Map<Integer,List<String>> MapOf_words_arrays = new HashMap<Integer,List<String>>();

I need to get the values of above Map in to one string array (e.g shown below) , .

["dog","cat"]
["book","pen","phone","waterbottle"]
.
.
.etc

I'm using the below statement

String wordlists = MapOf_words_arrays.values().toArray(new String[0]);

but I'm getting an error

Exception in thread "main" java.lang.ArrayStoreException: java.util.ArrayList$SubList at java.util.AbstractCollection.toArray(AbstractCollection.java:196) at ScrapePages.main(ScrapePages.java:98)

Can anybody help me out here?

Upvotes: 3

Views: 3827

Answers (7)

fps
fps

Reputation: 34480

Here's a way to do it with Java 8 features (but without the overhead of streams):

List<String> result = new ArrayList<>();
mapOfWordsArrays.values().forEach(result::addAll);

This iterates over all the values of the map, and adds each value (which is of type List<String>) to the result list. This is why I'm using the List.addAll method.

Another way would be to iterate directly on the entries of the map:

List<String> result = new ArrayList<>();
mapOfWordsArrays.forEach((k, v) -> result.addAll(v));

IMO, this is the most compact, yet readable and easiest way.

I suggest you check the docs of List.addAll, Iterable.forEach and Map.forEach methods for further details.

Note: I've changed the variables names to stick to Java naming conventions.

Upvotes: 0

Tharun
Tharun

Reputation: 311

Try this:

ArrayList<String> allStrings = new ArrayList<>();
for (List<String> list : MapOf_words_arrays.values()) {
    allStrings.addAll(list);
}
String[] stringArray = allStrings.toArray(new String[] {});  //The array you wanted

Upvotes: 1

Zabuzard
Zabuzard

Reputation: 25943

Explanation

ArrayStoreException means that you are trying to store the wrong type of elements into the wrong type of array (see its documentation).

You are calling

values().toArray(new String[0])

So you try to store something into an array which accepts String as its elements. However Map#values doesn't return String in your case, it returns a Collection containing elements of type List<String>. That's why it wants an array of type List, not String.


Solution

You first need to flatten all sub-lists into one. For this you have multiple options. The most straight-forward solution would be to iterate all elements and then add them into another List, then convert this list into an array:

List<String> valuesFlatten = new ArrayList<>();

// Flatten all values
for (List<String> valueContainer : MapOf_words_arrays.values()) {
    valuesFlatten.addAll(valueContainer);
}

// Create and fill the array
String[] result = new String[valuesFlatte.size()];
valuesFlatten.toArray(result);

Or more compact, a solution using Streams (Java 8):

String[] result = MapOf_words_arrays.values().stream()  // List<String>
    .flatMap(List::stream)                              // String
    .toArray(String[]::new)

Upvotes: 5

UniversE
UniversE

Reputation: 2506

Please consider an elegant Java 8 solution, if you can.

// compute the size of the target array
int size = map.values().stream().reduce(0,(k, l) -> k+l.size(), (l,r) ->l+r);
// allocate the target array
String[] test = new String[size];
// reduce the map to a list (this is in general more efficient than directly reducing it to an array)
map.values().stream().reduce(
    new ArrayList<String>(),
    (l, x) -> {l.addAll(x); return l;}
    ).toArray(test);

// test output that everything worked        
for (String s:test)
System.out.println(s);

Upvotes: 0

JRG
JRG

Reputation: 4187

Here is how you can convert Map<Integer, List<String>> to either List<String> or String[].

NOTE: at the end, checkout out the simplest way to convert it using Java 8 Streams

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MapClass {

    public static void main(String[] args) {
        Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
        map.put(1, Arrays.asList("11", "12", "13"));
        map.put(2, Arrays.asList("21", "22", "23"));
        // if you need list
        List<String> result = new ArrayList<String>();
        for (List<String> list : map.values()) {
            result.addAll(list);
        }
        System.out.println(result);

        // if you need array
        String[] array = result.toArray(new String[0]);
        System.out.println(Arrays.toString(array));

        // using streams
        List<String> java8List = map
                                .values()
                                .stream()
                                .flatMap(l -> l.stream())
                                .collect(Collectors.toList());
        System.out.println(java8List);

        // if you need array
        String[] arrays = java8List.toArray(new String[0]);
        System.out.println(Arrays.toString(arrays));
    }
}

Sample Run:

[11, 12, 13, 21, 22, 23]
[11, 12, 13, 21, 22, 23]
[11, 12, 13, 21, 22, 23]
[11, 12, 13, 21, 22, 23]

Upvotes: 0

anupam691997
anupam691997

Reputation: 310

Here is the full working demo of what you wanted

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {

        Map<Integer,List<String>> MapOf_words_arrays = new HashMap<Integer,List<String>>();

        ArrayList<String> s1=new ArrayList<>();
        s1.add("anupam");
        s1.add("lucky");

        ArrayList<String> s2=new ArrayList<>();
        s2.add("anu");
        s2.add("luck");

        MapOf_words_arrays.put(0,s1);
        MapOf_words_arrays.put(1,s2);

        ArrayList<String> final_ans=new ArrayList<String>();

        for(List<String> list : MapOf_words_arrays.values())
        {
            for(int i=0;i<list.size();i++)
            {
                final_ans.add(list.get(i));
            }
        }

        String[] myArray = final_ans.toArray(new String[final_ans.size()]);


        for(int b=0;b<myArray.length;b++)
            System.out.print(myArray[b]+" ");



    }
}

Upvotes: 0

Rehan Javed
Rehan Javed

Reputation: 436

You can do it by creating a Iterator from the map values. Then iterate through all values using the while loop and get all Strings from the lists and add them to a single ArrayList and convert it to String[]. :)

Here is working the code:

Map<Integer,List<String>> MapOf_words_arrays = new HashMap<Integer,List<String>>();
Iterator<List<String>> iterator = MapOf_words_arrays.values().iterator();

ArrayList<String> data = new ArrayList<String>();
List<String> tempList;
while(iterator.hasNext()){

    tempList = iterator.next();
    for(String item: tempList){
        data.add(item);
    }

}

// Here is your array with all strings.
String[] array = data.toArray(new String[]{});

Upvotes: 1

Related Questions