How can I convert ArrayList<Object> to ArrayList<String>? - java

ArrayList<Object> list = new ArrayList<Object>();
list.add(1);
list.add("Java");
list.add(3.14);
System.out.println(list.toString());
I tried:
ArrayList<String> list2 = (String)list;
But it gave me a compile error.

Since this is actually not a list of strings, the easiest way is to loop over it and convert each item into a new list of strings yourself:
List<String> strings = list.stream()
.map(object -> Objects.toString(object, null))
.toList();
Or when you're not on Java 16 yet:
List<String> strings = list.stream()
.map(object -> Objects.toString(object, null))
.collect(Collectors.toList());
Or when you're not on Java 8 yet:
List<String> strings = new ArrayList<>(list.size());
for (Object object : list) {
strings.add(Objects.toString(object, null));
}
Or when you're not on Java 7 yet:
List<String> strings = new ArrayList<String>(list.size());
for (Object object : list) {
strings.add(object != null ? object.toString() : null);
}
Note that you should be declaring against the interface (java.util.List in this case), not the implementation.

It's not safe to do that!
Imagine if you had:
ArrayList<Object> list = new ArrayList<Object>();
list.add(new Employee("Jonh"));
list.add(new Car("BMW","M3"));
list.add(new Chocolate("Twix"));
It wouldn't make sense to convert the list of those Objects to any type.

Using Java 8 you can do:
List<Object> list = ...;
List<String> strList = list.stream()
.map( Object::toString )
.collect( Collectors.toList() );

You can use wildcard to do this as following
ArrayList<String> strList = (ArrayList<String>)(ArrayList<?>)(list);

If you want to do it the dirty way, try this.
#SuppressWarnings("unchecked")
public ArrayList<String> convert(ArrayList<Object> a) {
return (ArrayList) a;
}
Advantage: here you save time by not iterating over all objects.
Disadvantage: may produce a hole in your foot.

Using guava:
List<String> stringList=Lists.transform(list,new Function<Object,String>(){
#Override
public String apply(Object arg0) {
if(arg0!=null)
return arg0.toString();
else
return "null";
}
});

Here is another alternative using Guava
List<Object> lst ...
List<String> ls = Lists.transform(lst, Functions.toStringFunction());

Your code ArrayList<String> list2 = (String)list; does not compile because list2 is not of type String. But that is not the only problem.

Using Java 8 lambda:
ArrayList<Object> obj = new ArrayList<>();
obj.add(1);
obj.add("Java");
obj.add(3.14);
ArrayList<String> list = new ArrayList<>();
obj.forEach((xx) -> list.add(String.valueOf(xx)));

With Java Generics Takes a list of X and returns a list of T that extends or implements X, Sweet!
// the cast is is actually checked via the method API
#SuppressWarnings("unchecked")
public static <T extends X, X> ArrayList<T> convertToClazz(ArrayList<X> from, Class<X> inClazz, Class<T> outClazz) {
ArrayList<T> to = new ArrayList<T>();
for (X data : from) {
to.add((T) data);
}
return to;
}

A simple solution:
List<Object> lst =listOfTypeObject;
ArrayList<String> aryLst = new ArrayList<String>();
for (int i = 0; i < lst.size(); i++) {
aryLst.add(lst.get(i).toString());
}
Note: this works when the list contains all the elements of datatype String.

Related

How to join two arrayList in java? [duplicate]

Conditions: do not modify the original lists; JDK only, no external libraries. Bonus points for a one-liner or a JDK 1.3 version.
Is there a simpler way than:
List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);
In Java 8:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
.collect(Collectors.toList());
Java 16+:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).toList();
Off the top of my head, I can shorten it by one line:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
You could use the Apache commons-collections library:
List<String> newList = ListUtils.union(list1, list2);
Another Java 8 one-liner:
List<String> newList = Stream.of(listOne, listTwo)
.flatMap(Collection::stream)
.collect(Collectors.toList());
As a bonus, since Stream.of() is variadic, you may concatenate as many lists as you like.
List<String> newList = Stream.of(listOne, listTwo, listThree)
.flatMap(Collection::stream)
.collect(Collectors.toList());
One of your requirements is to preserve the original lists. If you create a new list and use addAll(), you are effectively doubling the number of references to the objects in your lists. This could lead to memory problems if your lists are very large.
If you don't need to modify the concatenated result, you can avoid this using a custom list implementation. The custom implementation class is more than one line, obviously...but using it is short and sweet.
CompositeUnmodifiableList.java:
public class CompositeUnmodifiableList<E> extends AbstractList<E> {
private final List<? extends E> list1;
private final List<? extends E> list2;
public CompositeUnmodifiableList(List<? extends E> list1, List<? extends E> list2) {
this.list1 = list1;
this.list2 = list2;
}
#Override
public E get(int index) {
if (index < list1.size()) {
return list1.get(index);
}
return list2.get(index-list1.size());
}
#Override
public int size() {
return list1.size() + list2.size();
}
}
Usage:
List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);
Probably not simpler, but intriguing and ugly:
List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };
Don't use it in production code... ;)
Not simpler, but without resizing overhead:
List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);
Found this question looking to concatenate arbitrary amount of lists, not minding external libraries. So, perhaps it will help someone else:
com.google.common.collect.Iterables#concat()
Useful if you want to apply the same logic to a number of different collections in one for().
Java 8 (Stream.of and Stream.concat)
The proposed solution is for three lists though it can be applied for two lists as well. In Java 8 we can make use of Stream.of or Stream.concat as:
List<String> result1 = Stream.concat(Stream.concat(list1.stream(),list2.stream()),list3.stream()).collect(Collectors.toList());
List<String> result2 = Stream.of(list1,list2,list3).flatMap(Collection::stream).collect(Collectors.toList());
Stream.concat takes two streams as input and creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream. As we have three lists we have used this method (Stream.concat) two times.
We can also write a utility class with a method that takes any number of lists (using varargs) and returns a concatenated list as:
public static <T> List<T> concatenateLists(List<T>... collections) {
return Arrays.stream(collections).flatMap(Collection::stream).collect(Collectors.toList());
}
Then we can make use of this method as:
List<String> result3 = Utils.concatenateLists(list1,list2,list3);
Here is a java 8 solution using two lines:
List<Object> newList = new ArrayList<>();
Stream.of(list1, list2).forEach(newList::addAll);
Be aware that this method should not be used if
the origin of newList is not known and it may already be shared with other threads
the stream that modifies newList is a parallel stream and access to newList is not synchronized or threadsafe
due to side effect considerations.
Both of the above conditions do not apply for the above case of joining two lists, so this is safe.
Based on this answer to another question.
This is simple and just one line, but will add the contents of listTwo to listOne. Do you really need to put the contents in a third list?
Collections.addAll(listOne, listTwo.toArray());
Slightly simpler:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
A little shorter would be:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
You can create your generic Java 8 utility method to concat any number of lists.
#SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}
In Java 8 (the other way):
List<?> newList =
Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toList());
You can do a oneliner if the target list is predeclared.
(newList = new ArrayList<String>(list1)).addAll(list2);
another one liner solution using Java8 stream, since flatMap solution is already posted, here is a solution without flatMap
List<E> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
or
List<E> ints = Stream.of(list1, list2).collect(ArrayList::new, List::addAll, List::addAll);
code
List<List<Integer>> lol = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
List<Integer> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
System.out.println(lol);
System.out.println(li);
output
[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]
We can join 2 lists using java8 with 2 approaches.
List<String> list1 = Arrays.asList("S", "T");
List<String> list2 = Arrays.asList("U", "V");
1) Using concat :
List<String> collect2 = Stream.concat(list1.stream(), list2.stream()).collect(toList());
System.out.println("collect2 = " + collect2); // collect2 = [S, T, U, V]
2) Using flatMap :
List<String> collect3 = Stream.of(list1, list2).flatMap(Collection::stream).collect(toList());
System.out.println("collect3 = " + collect3); // collect3 = [S, T, U, V]
Almost of answers suggest to use an ArrayList.
List<String> newList = new LinkedList<>(listOne);
newList.addAll(listTwo);
Prefer to use a LinkedList for efficient add operations.
ArrayList add is O(1) amortized, but O(n) worst-case since the array must be resized and copied.
While LinkedList add is always constant O(1).
more infos https://stackoverflow.com/a/322742/311420
The smartest in my opinion:
/**
* #param smallLists
* #return one big list containing all elements of the small ones, in the same order.
*/
public static <E> List<E> concatenate (final List<E> ... smallLists)
{
final ArrayList<E> bigList = new ArrayList<E>();
for (final List<E> list: smallLists)
{
bigList.addAll(list);
}
return bigList;
}
You could do it with a static import and a helper class
nb the generification of this class could probably be improved
public class Lists {
private Lists() { } // can't be instantiated
public static List<T> join(List<T>... lists) {
List<T> result = new ArrayList<T>();
for(List<T> list : lists) {
result.addAll(list);
}
return results;
}
}
Then you can do things like
import static Lists.join;
List<T> result = join(list1, list2, list3, list4);
Java 8 version with support for joining by object key:
public List<SomeClass> mergeLists(final List<SomeClass> left, final List<SomeClass> right, String primaryKey) {
final Map<Object, SomeClass> mergedList = new LinkedHashMap<>();
Stream.concat(left.stream(), right.stream())
.map(someObject -> new Pair<Object, SomeClass>(someObject.getSomeKey(), someObject))
.forEach(pair-> mergedList.put(pair.getKey(), pair.getValue()));
return new ArrayList<>(mergedList.values());
}
public static <T> List<T> merge(List<T>... args) {
final List<T> result = new ArrayList<>();
for (List<T> list : args) {
result.addAll(list);
}
return result;
}
Use a Helper class.
I suggest:
public static <E> Collection<E> addAll(Collection<E> dest, Collection<? extends E>... src) {
for(Collection<? extends E> c : src) {
dest.addAll(c);
}
return dest;
}
public static void main(String[] args) {
System.out.println(addAll(new ArrayList<Object>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));
// does not compile
// System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));
System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList(4, 5, 6)));
}
public static <T> List<T> merge(#Nonnull final List<T>... list) {
// calculate length first
int mergedLength = 0;
for (List<T> ts : list) {
mergedLength += ts.size();
}
final List<T> mergedList = new ArrayList<>(mergedLength);
for (List<T> ts : list) {
mergedList.addAll(ts);
}
return mergedList;
}
My favourite way, using fluent api and Guava:
List<String> combined = ImmutableList.<String>builder().addAll(list1).addAll(list2).build()
I'm not claiming that it's simple, but you mentioned bonus for one-liners ;-)
Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
new Vector(list1).elements(),
new Vector(list2).elements(),
...
}))
No way near one-liner, but I think this is the simplest:
List<String> newList = new ArrayList<String>(l1);
newList.addAll(l2);
for(String w:newList)
System.out.printf("%s ", w);
Here's an approach using streams and java 8 if your lists have different types and you want to combine them to a list of another type.
public static void main(String[] args) {
List<String> list2 = new ArrayList<>();
List<Pair<Integer, String>> list1 = new ArrayList<>();
list2.add("asd");
list2.add("asdaf");
list1.add(new Pair<>(1, "werwe"));
list1.add(new Pair<>(2, "tyutyu"));
Stream stream = Stream.concat(list1.stream(), list2.stream());
List<Pair<Integer, String>> res = (List<Pair<Integer, String>>) stream
.map(item -> {
if (item instanceof String) {
return new Pair<>(0, item);
}
else {
return new Pair<>(((Pair<Integer, String>)item).getKey(), ((Pair<Integer, String>)item).getValue());
}
})
.collect(Collectors.toList());
}
If you want to do this statically you can the following.
The examples uses 2 EnumSets in natural-order (==Enum-order) A, B and joins then in an ALL list.
public static final EnumSet<MyType> CATEGORY_A = EnumSet.of(A_1, A_2);
public static final EnumSet<MyType> CATEGORY_B = EnumSet.of(B_1, B_2, B_3);
public static final List<MyType> ALL =
Collections.unmodifiableList(
new ArrayList<MyType>(CATEGORY_A.size() + CATEGORY_B.size())
{{
addAll(CATEGORY_A);
addAll(CATEGORY_B);
}}
);

How should I instantiate List<List<String>> in Java

I have the following code:
List<List<String>> allData= getData()
if (allData== null)
allData= new ArrayList<ArrayList<String>>();
// populate allData below
Now I want to initialize allData but I get Type mismatch: cannot convert from ArrayList<ArrayList<String>> to List<List<String>>. What is the correct way I can initialize this?
It is not possible to return ArrayList<ArrayList<String>> from getData()
Thanks!
You do it very simply:
allData = new ArrayList<>();
Then you can add new lists to allData:
List innerList = new ArrayList<>();
innerList.add("some string");
// .... etc ...
allData.add(innerList);
You cannot redefine the generic type of the reference when you instantiate the concrete implementation. The reference is List<List<String>> so the assigned List must be capable of accepting any List<String> as an element. When you instantiated your instance, you attempted to limit this to ArrayList<String>.
The explicit solution is:
allData = new ArrayList<List<String>>();
or more simply as:
allData = new ArrayList<>();
A simple example of getData might be as below -
public static List<List<String>> getData(String fileName){
List<List<String>> content = null;
try (Stream<String> lines = Files.lines(Paths.get(fileName ))) {
content = lines
.map(l -> l.split(" "))
.map(Arrays::asList)
.collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return content;
}

Convert from map to arraylist

I tried to convert a Map<String,ArrayList<Object>> to ArrayList<Object> using this code:
Collection<ArrayList<Object>> coll = map().values();
List list = new ArrayList(coll);
ArrayList<Object> arrayList = new ArrayList<>(list.size());
arrayList.addAll(list);
However, the arraylist I got still groups objects by key still as collection.
How can I convert to ArrayList of separate Objects?
You can use Java 8 Streams:
List<Object> list = map.values().stream()
.flatMap(ArrayList::stream)
.collect(Collectors.toList());
Without Streams, you'll have to iterate over the elements of your first List and call arrayList.addAll() for each of them separately.
A non stream version would be:
List<Object> accumulator = new ArrayList<>();
for(ArrayList<Object> a : map.values())
accumulator.addAll(a);
same result can be achieved by using following traditional approach as well -
Map<String, ArrayList<Object>> map = new HashMap<>();
ArrayList<Object> objects1 = new ArrayList<>();
objects1.add("data1");
objects1.add("data2");
objects1.add("data3");
map.put("key1", objects1);
ArrayList<Object> objects2 = new ArrayList<>();
objects2.add("data1");
objects2.add("data2");
objects2.add("data3");
map.put("key2", objects2);
Collection<ArrayList<Object>> collections = map.values();
List<Object> list = new ArrayList<>();
for(ArrayList<Object> collection : collections) {
for(Object obj : collection) {
list.add(obj);
}
}
System.out.println(list);
It will print the output as :
[data1, data2, data3, data1, data2, data3]

Lambda expression to add objects from one list to another type of list

There is a List<MyObject> and it's objects are required to create object that will be added to another List with different elements : List<OtherObject>.
This is how I am doing,
List<MyObject> myList = returnsList();
List<OtherObj> emptyList = new ArrayList();
for(MyObject obj: myList) {
OtherObj oo = new OtherObj();
oo.setUserName(obj.getName());
oo.setUserAge(obj.getMaxAge());
emptyList.add(oo);
}
I'm looking for a lamdba expression to do the exact same thing.
If you define constructor OtherObj(String name, Integer maxAge) you can do it this java8 style:
myList.stream()
.map(obj -> new OtherObj(obj.getName(), obj.getMaxAge()))
.collect(Collectors.toList());
This will map all objects in list myList to OtherObj and collect it to new List containing these objects.
You can create a constructor in OtherObject which uses MyObject attributes,
public OtherObject(MyObject myObj) {
this.username = myObj.getName();
this.userAge = myObj.getAge();
}
and you can do following to create OtherObjects from MyObjects,
myObjs.stream().map(OtherObject::new).collect(Collectors.toList());
I see that this is quite old post. However, this is my take on this based on the previous answers. The only modification in my answer is usage of .collect(ArrayList::new, ArrayList::add,ArrayList:addAll).
Sample code :
List<OtherObj> emptyList = myList.stream()
.map(obj -> {
OtherObj oo = new OtherObj();
oo.setUserName(obj.getName());
oo.setUserAge(obj.getMaxAge());
return oo; })
.collect(ArrayList::new, ArrayList::add,ArrayList::addAll);

How to convert a SparseArray to ArrayList?

I know this is possible:
Map<Integer, Object> map = new HashMap<Integer, Object>();
...
List<Object> arrayList = new ArrayList<Object>(map.values());
But according to android SparseArray<Object> is more efficient, hence, I am wondering if it is possible to convert a SparseArray to Arraylist.
Much appreciate any input.
This will get just the values, ignoring gaps between indices (as your existing Map solution does):
public static <C> List<C> asList(SparseArray<C> sparseArray) {
if (sparseArray == null) return null;
List<C> arrayList = new ArrayList<C>(sparseArray.size());
for (int i = 0; i < sparseArray.size(); i++)
arrayList.add(sparseArray.valueAt(i));
return arrayList;
}
ArrayMap looks like a better choice, which is available since API 19.
Kotlin version:
fun <T> SparseArray<T>.values(): List<T> {
val list = ArrayList<T>()
forEach { _, value ->
list.add(value)
}
return list.toList()

Categories