How to concatenate lists into one list
I have a list of values, some of which could be lists/collections or single values. In JavaScript notation it might look like:
const input = [1,2,[3,4], [5,6], 7];
and I want to get:
const concatenated = [1,2,3,4,5,6,7];
So I have this Java code:
ArrayList<T> concatenated = new ArrayList<>();
for (T v : input) {
try{
concatenated.addAll((Collection) v);
}
catch (Exception e1){
try{
concatenated.addAll((List) v);
}
catch (Exception e2){
concatenated.add(v);
}
}
}
but that code seems pretty terrible to me. First I don't know if attempting to cast to List or Collection is sufficient - are there are other types I should attempt to cast to? Are there any errors I shouldn't ignore?
How to do this right?
java arraylist concatenation
add a comment |
I have a list of values, some of which could be lists/collections or single values. In JavaScript notation it might look like:
const input = [1,2,[3,4], [5,6], 7];
and I want to get:
const concatenated = [1,2,3,4,5,6,7];
So I have this Java code:
ArrayList<T> concatenated = new ArrayList<>();
for (T v : input) {
try{
concatenated.addAll((Collection) v);
}
catch (Exception e1){
try{
concatenated.addAll((List) v);
}
catch (Exception e2){
concatenated.add(v);
}
}
}
but that code seems pretty terrible to me. First I don't know if attempting to cast to List or Collection is sufficient - are there are other types I should attempt to cast to? Are there any errors I shouldn't ignore?
How to do this right?
java arraylist concatenation
1
fyi Java does not support mixed match type in list as you have ininput
, it can be likeinput = [[1],[2],[3,4], [5,6], [7]];
– dkb
3 hours ago
and there could benull
values there (exception handling is for what otherwise)?
– nullpointer
3 hours ago
I think you can do thisconcatenated.addAll((Iterable) v);
instead of try to cast to bothCollection
andList
.
– MrCholo
3 hours ago
2
@MrCholo An array list does not have an overload foraddAll
withIterable
. The simplest interface you can use isCollection
See here. The reason being thatIterable
doesn't have to persist the data. It can be a read once, or even random in what data is returned. All it specifies is that you can iterate on it.
– flakes
2 hours ago
add a comment |
I have a list of values, some of which could be lists/collections or single values. In JavaScript notation it might look like:
const input = [1,2,[3,4], [5,6], 7];
and I want to get:
const concatenated = [1,2,3,4,5,6,7];
So I have this Java code:
ArrayList<T> concatenated = new ArrayList<>();
for (T v : input) {
try{
concatenated.addAll((Collection) v);
}
catch (Exception e1){
try{
concatenated.addAll((List) v);
}
catch (Exception e2){
concatenated.add(v);
}
}
}
but that code seems pretty terrible to me. First I don't know if attempting to cast to List or Collection is sufficient - are there are other types I should attempt to cast to? Are there any errors I shouldn't ignore?
How to do this right?
java arraylist concatenation
I have a list of values, some of which could be lists/collections or single values. In JavaScript notation it might look like:
const input = [1,2,[3,4], [5,6], 7];
and I want to get:
const concatenated = [1,2,3,4,5,6,7];
So I have this Java code:
ArrayList<T> concatenated = new ArrayList<>();
for (T v : input) {
try{
concatenated.addAll((Collection) v);
}
catch (Exception e1){
try{
concatenated.addAll((List) v);
}
catch (Exception e2){
concatenated.add(v);
}
}
}
but that code seems pretty terrible to me. First I don't know if attempting to cast to List or Collection is sufficient - are there are other types I should attempt to cast to? Are there any errors I shouldn't ignore?
How to do this right?
java arraylist concatenation
java arraylist concatenation
edited 1 hour ago
MrCholo
asked 3 hours ago
MrCholoMrCholo
1,270931
1,270931
1
fyi Java does not support mixed match type in list as you have ininput
, it can be likeinput = [[1],[2],[3,4], [5,6], [7]];
– dkb
3 hours ago
and there could benull
values there (exception handling is for what otherwise)?
– nullpointer
3 hours ago
I think you can do thisconcatenated.addAll((Iterable) v);
instead of try to cast to bothCollection
andList
.
– MrCholo
3 hours ago
2
@MrCholo An array list does not have an overload foraddAll
withIterable
. The simplest interface you can use isCollection
See here. The reason being thatIterable
doesn't have to persist the data. It can be a read once, or even random in what data is returned. All it specifies is that you can iterate on it.
– flakes
2 hours ago
add a comment |
1
fyi Java does not support mixed match type in list as you have ininput
, it can be likeinput = [[1],[2],[3,4], [5,6], [7]];
– dkb
3 hours ago
and there could benull
values there (exception handling is for what otherwise)?
– nullpointer
3 hours ago
I think you can do thisconcatenated.addAll((Iterable) v);
instead of try to cast to bothCollection
andList
.
– MrCholo
3 hours ago
2
@MrCholo An array list does not have an overload foraddAll
withIterable
. The simplest interface you can use isCollection
See here. The reason being thatIterable
doesn't have to persist the data. It can be a read once, or even random in what data is returned. All it specifies is that you can iterate on it.
– flakes
2 hours ago
1
1
fyi Java does not support mixed match type in list as you have in
input
, it can be like input = [[1],[2],[3,4], [5,6], [7]];
– dkb
3 hours ago
fyi Java does not support mixed match type in list as you have in
input
, it can be like input = [[1],[2],[3,4], [5,6], [7]];
– dkb
3 hours ago
and there could be
null
values there (exception handling is for what otherwise)?– nullpointer
3 hours ago
and there could be
null
values there (exception handling is for what otherwise)?– nullpointer
3 hours ago
I think you can do this
concatenated.addAll((Iterable) v);
instead of try to cast to both Collection
and List
.– MrCholo
3 hours ago
I think you can do this
concatenated.addAll((Iterable) v);
instead of try to cast to both Collection
and List
.– MrCholo
3 hours ago
2
2
@MrCholo An array list does not have an overload for
addAll
with Iterable
. The simplest interface you can use is Collection
See here. The reason being that Iterable
doesn't have to persist the data. It can be a read once, or even random in what data is returned. All it specifies is that you can iterate on it.– flakes
2 hours ago
@MrCholo An array list does not have an overload for
addAll
with Iterable
. The simplest interface you can use is Collection
See here. The reason being that Iterable
doesn't have to persist the data. It can be a read once, or even random in what data is returned. All it specifies is that you can iterate on it.– flakes
2 hours ago
add a comment |
3 Answers
3
active
oldest
votes
The code doesn't need Exception
handling as such unless there are null
values in the lists. It should be sufficient though in your case to just cast basis of instanceOf
as:
// Edit: Since the type of the input `Collection` is not bound strictly
List<Object> flatten(Collection<?> input) {
List<Object> concatenated = new ArrayList<>();
for (Object v : input) {
if (v instanceof Collection) {
concatenated.addAll(flatten((Collection<?>) v));
} else {
concatenated.add(v);
}
}
return concatenated;
}
using it further on jshell gives me this output:
jshell> List<Object> list = List.of(1,2,List.of(3,4),List.of(5,6),7)
list ==> [1, 2, [3, 4], [5, 6], 7]
jshell> concatenateList(list)
$3 ==> [1, 2, 3, 4, 5, 6, 7]
:
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
1
@MrCholonull
is a valid argument toinstanceof
. it will always return false. And anArrayList
can acceptnull
as an input toadd
.
– flakes
2 hours ago
2
I think a nice addition to this solution would be to make it recursive. ieconcatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might beflatten
– flakes
2 hours ago
1
@MrCholoList
extendsCollection
– nullpointer
2 hours ago
1
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basicCollection
orList
orMap
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.
– flakes
1 hour ago
|
show 15 more comments
Use of Exceptions
to control application flow/business logic is an anti-pattern. You can read more about it here, here and here.
Regarding storing different types of elements in Collections could be difficult to debug and maintain. You can write your own wrapper and encapsulate the handling of it from usage. You can refer this for an inspiration.
add a comment |
As others have mentioned, using exceptions for control flow is not ideal. You can instead use the instanceof
operator to test if an element is a Collection
. The answer by nullpointer shows a good example of this. If you want an more generic option you could also do something like:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public static <E> List<E> deepFlatten(final Iterable<?> iterable, final Class<E> type) {
if (type.isPrimitive() || type.isArray() || Iterable.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(
"type must not denote a primitive, array, or java.lang.Iterable type: " + type);
}
final List<E> result = new ArrayList<>();
for (final Object element : iterable) {
if (element instanceof Iterable<?>) {
result.addAll(deepFlatten((Iterable<?>) element, type)); // recursion
} else if (element != null && element.getClass().isArray()) {
if (element instanceof Object) {
result.addAll(deepFlatten(Arrays.asList((Object) element), type)); // recursion
} else { // primitive array
final Iterable<?> itrArray = IntStream.range(0, Array.getLength(element))
.mapToObj(index -> Array.get(element, index))::iterator; // method reference
result.addAll(deepFlatten(itrArray, type)); // recursion
}
} else {
/*
* Will throw ClassCastException if any element is not an instance
* of "type". You could also throw a NullPointerException here if
* you don't want to allow null elements.
*/
result.add(type.cast(element));
}
}
return result;
}
This also handles "embedded" arrays, as well as Iterable
s, through recursion. Note it doesn't handle Map
s because of the ambiguity; should we flatten the keys or the values—or both?
Calling the above with:
Iterable<?> iterable = List.of(
"A", "B", "C", "D",
List.of("E", "F", List.of("G", "H"), "I", "J"),
"K",
new String{"L", "M", "N", "O", "P"},
new String{{"Q", "R"}, {"S", "T"}, {"U"}, {"V"}},
new Object{"W", "X"},
"Y", "Z"
);
List<String> flattened = deepFlatten(iterable, String.class);
System.out.println(flattened);
Gave me:
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
Note that the letters are in order because List
s and arrays have guaranteed iteration orders. If your Iterable
contained a Set
the result of the deepFlatten
may not be in the same order each time.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54624265%2fhow-to-concatenate-lists-into-one-list%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The code doesn't need Exception
handling as such unless there are null
values in the lists. It should be sufficient though in your case to just cast basis of instanceOf
as:
// Edit: Since the type of the input `Collection` is not bound strictly
List<Object> flatten(Collection<?> input) {
List<Object> concatenated = new ArrayList<>();
for (Object v : input) {
if (v instanceof Collection) {
concatenated.addAll(flatten((Collection<?>) v));
} else {
concatenated.add(v);
}
}
return concatenated;
}
using it further on jshell gives me this output:
jshell> List<Object> list = List.of(1,2,List.of(3,4),List.of(5,6),7)
list ==> [1, 2, [3, 4], [5, 6], 7]
jshell> concatenateList(list)
$3 ==> [1, 2, 3, 4, 5, 6, 7]
:
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
1
@MrCholonull
is a valid argument toinstanceof
. it will always return false. And anArrayList
can acceptnull
as an input toadd
.
– flakes
2 hours ago
2
I think a nice addition to this solution would be to make it recursive. ieconcatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might beflatten
– flakes
2 hours ago
1
@MrCholoList
extendsCollection
– nullpointer
2 hours ago
1
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basicCollection
orList
orMap
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.
– flakes
1 hour ago
|
show 15 more comments
The code doesn't need Exception
handling as such unless there are null
values in the lists. It should be sufficient though in your case to just cast basis of instanceOf
as:
// Edit: Since the type of the input `Collection` is not bound strictly
List<Object> flatten(Collection<?> input) {
List<Object> concatenated = new ArrayList<>();
for (Object v : input) {
if (v instanceof Collection) {
concatenated.addAll(flatten((Collection<?>) v));
} else {
concatenated.add(v);
}
}
return concatenated;
}
using it further on jshell gives me this output:
jshell> List<Object> list = List.of(1,2,List.of(3,4),List.of(5,6),7)
list ==> [1, 2, [3, 4], [5, 6], 7]
jshell> concatenateList(list)
$3 ==> [1, 2, 3, 4, 5, 6, 7]
:
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
1
@MrCholonull
is a valid argument toinstanceof
. it will always return false. And anArrayList
can acceptnull
as an input toadd
.
– flakes
2 hours ago
2
I think a nice addition to this solution would be to make it recursive. ieconcatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might beflatten
– flakes
2 hours ago
1
@MrCholoList
extendsCollection
– nullpointer
2 hours ago
1
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basicCollection
orList
orMap
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.
– flakes
1 hour ago
|
show 15 more comments
The code doesn't need Exception
handling as such unless there are null
values in the lists. It should be sufficient though in your case to just cast basis of instanceOf
as:
// Edit: Since the type of the input `Collection` is not bound strictly
List<Object> flatten(Collection<?> input) {
List<Object> concatenated = new ArrayList<>();
for (Object v : input) {
if (v instanceof Collection) {
concatenated.addAll(flatten((Collection<?>) v));
} else {
concatenated.add(v);
}
}
return concatenated;
}
using it further on jshell gives me this output:
jshell> List<Object> list = List.of(1,2,List.of(3,4),List.of(5,6),7)
list ==> [1, 2, [3, 4], [5, 6], 7]
jshell> concatenateList(list)
$3 ==> [1, 2, 3, 4, 5, 6, 7]
:
The code doesn't need Exception
handling as such unless there are null
values in the lists. It should be sufficient though in your case to just cast basis of instanceOf
as:
// Edit: Since the type of the input `Collection` is not bound strictly
List<Object> flatten(Collection<?> input) {
List<Object> concatenated = new ArrayList<>();
for (Object v : input) {
if (v instanceof Collection) {
concatenated.addAll(flatten((Collection<?>) v));
} else {
concatenated.add(v);
}
}
return concatenated;
}
using it further on jshell gives me this output:
jshell> List<Object> list = List.of(1,2,List.of(3,4),List.of(5,6),7)
list ==> [1, 2, [3, 4], [5, 6], 7]
jshell> concatenateList(list)
$3 ==> [1, 2, 3, 4, 5, 6, 7]
:
edited 2 hours ago
answered 3 hours ago


nullpointernullpointer
48.8k11101196
48.8k11101196
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
1
@MrCholonull
is a valid argument toinstanceof
. it will always return false. And anArrayList
can acceptnull
as an input toadd
.
– flakes
2 hours ago
2
I think a nice addition to this solution would be to make it recursive. ieconcatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might beflatten
– flakes
2 hours ago
1
@MrCholoList
extendsCollection
– nullpointer
2 hours ago
1
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basicCollection
orList
orMap
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.
– flakes
1 hour ago
|
show 15 more comments
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
1
@MrCholonull
is a valid argument toinstanceof
. it will always return false. And anArrayList
can acceptnull
as an input toadd
.
– flakes
2 hours ago
2
I think a nice addition to this solution would be to make it recursive. ieconcatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might beflatten
– flakes
2 hours ago
1
@MrCholoList
extendsCollection
– nullpointer
2 hours ago
1
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basicCollection
orList
orMap
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.
– flakes
1 hour ago
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
yeah but what about Collection? Can you use instanceof on Iterable? Collection and List both implement Iterable, so that might work
– MrCholo
3 hours ago
1
1
@MrCholo
null
is a valid argument to instanceof
. it will always return false. And an ArrayList
can accept null
as an input to add
.– flakes
2 hours ago
@MrCholo
null
is a valid argument to instanceof
. it will always return false. And an ArrayList
can accept null
as an input to add
.– flakes
2 hours ago
2
2
I think a nice addition to this solution would be to make it recursive. ie
concatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might be flatten
– flakes
2 hours ago
I think a nice addition to this solution would be to make it recursive. ie
concatenated.addAll(concatenateList((List<T>) v))
This way you can handle multiple levels of nesting. A better name on this method might be flatten
– flakes
2 hours ago
1
1
@MrCholo
List
extends Collection
– nullpointer
2 hours ago
@MrCholo
List
extends Collection
– nullpointer
2 hours ago
1
1
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basic
Collection
or List
or Map
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.– flakes
1 hour ago
@nullpointer It's an interesting problem! I have tried to solve this problem before (when dealing with examining JSON data without having a schema ahead of time) and I don't think Java has a good model for dealing with this. The root problem is that a basic
Collection
or List
or Map
interface does not account for nested hierarchies of data when specializing the container. Other languages combat this problem differently, say through the use of pattern matching rather than strict class matching. A good example of tackling this is in Python's new type hints system.– flakes
1 hour ago
|
show 15 more comments
Use of Exceptions
to control application flow/business logic is an anti-pattern. You can read more about it here, here and here.
Regarding storing different types of elements in Collections could be difficult to debug and maintain. You can write your own wrapper and encapsulate the handling of it from usage. You can refer this for an inspiration.
add a comment |
Use of Exceptions
to control application flow/business logic is an anti-pattern. You can read more about it here, here and here.
Regarding storing different types of elements in Collections could be difficult to debug and maintain. You can write your own wrapper and encapsulate the handling of it from usage. You can refer this for an inspiration.
add a comment |
Use of Exceptions
to control application flow/business logic is an anti-pattern. You can read more about it here, here and here.
Regarding storing different types of elements in Collections could be difficult to debug and maintain. You can write your own wrapper and encapsulate the handling of it from usage. You can refer this for an inspiration.
Use of Exceptions
to control application flow/business logic is an anti-pattern. You can read more about it here, here and here.
Regarding storing different types of elements in Collections could be difficult to debug and maintain. You can write your own wrapper and encapsulate the handling of it from usage. You can refer this for an inspiration.
answered 3 hours ago
Ashutosh VaidyaAshutosh Vaidya
539
539
add a comment |
add a comment |
As others have mentioned, using exceptions for control flow is not ideal. You can instead use the instanceof
operator to test if an element is a Collection
. The answer by nullpointer shows a good example of this. If you want an more generic option you could also do something like:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public static <E> List<E> deepFlatten(final Iterable<?> iterable, final Class<E> type) {
if (type.isPrimitive() || type.isArray() || Iterable.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(
"type must not denote a primitive, array, or java.lang.Iterable type: " + type);
}
final List<E> result = new ArrayList<>();
for (final Object element : iterable) {
if (element instanceof Iterable<?>) {
result.addAll(deepFlatten((Iterable<?>) element, type)); // recursion
} else if (element != null && element.getClass().isArray()) {
if (element instanceof Object) {
result.addAll(deepFlatten(Arrays.asList((Object) element), type)); // recursion
} else { // primitive array
final Iterable<?> itrArray = IntStream.range(0, Array.getLength(element))
.mapToObj(index -> Array.get(element, index))::iterator; // method reference
result.addAll(deepFlatten(itrArray, type)); // recursion
}
} else {
/*
* Will throw ClassCastException if any element is not an instance
* of "type". You could also throw a NullPointerException here if
* you don't want to allow null elements.
*/
result.add(type.cast(element));
}
}
return result;
}
This also handles "embedded" arrays, as well as Iterable
s, through recursion. Note it doesn't handle Map
s because of the ambiguity; should we flatten the keys or the values—or both?
Calling the above with:
Iterable<?> iterable = List.of(
"A", "B", "C", "D",
List.of("E", "F", List.of("G", "H"), "I", "J"),
"K",
new String{"L", "M", "N", "O", "P"},
new String{{"Q", "R"}, {"S", "T"}, {"U"}, {"V"}},
new Object{"W", "X"},
"Y", "Z"
);
List<String> flattened = deepFlatten(iterable, String.class);
System.out.println(flattened);
Gave me:
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
Note that the letters are in order because List
s and arrays have guaranteed iteration orders. If your Iterable
contained a Set
the result of the deepFlatten
may not be in the same order each time.
add a comment |
As others have mentioned, using exceptions for control flow is not ideal. You can instead use the instanceof
operator to test if an element is a Collection
. The answer by nullpointer shows a good example of this. If you want an more generic option you could also do something like:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public static <E> List<E> deepFlatten(final Iterable<?> iterable, final Class<E> type) {
if (type.isPrimitive() || type.isArray() || Iterable.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(
"type must not denote a primitive, array, or java.lang.Iterable type: " + type);
}
final List<E> result = new ArrayList<>();
for (final Object element : iterable) {
if (element instanceof Iterable<?>) {
result.addAll(deepFlatten((Iterable<?>) element, type)); // recursion
} else if (element != null && element.getClass().isArray()) {
if (element instanceof Object) {
result.addAll(deepFlatten(Arrays.asList((Object) element), type)); // recursion
} else { // primitive array
final Iterable<?> itrArray = IntStream.range(0, Array.getLength(element))
.mapToObj(index -> Array.get(element, index))::iterator; // method reference
result.addAll(deepFlatten(itrArray, type)); // recursion
}
} else {
/*
* Will throw ClassCastException if any element is not an instance
* of "type". You could also throw a NullPointerException here if
* you don't want to allow null elements.
*/
result.add(type.cast(element));
}
}
return result;
}
This also handles "embedded" arrays, as well as Iterable
s, through recursion. Note it doesn't handle Map
s because of the ambiguity; should we flatten the keys or the values—or both?
Calling the above with:
Iterable<?> iterable = List.of(
"A", "B", "C", "D",
List.of("E", "F", List.of("G", "H"), "I", "J"),
"K",
new String{"L", "M", "N", "O", "P"},
new String{{"Q", "R"}, {"S", "T"}, {"U"}, {"V"}},
new Object{"W", "X"},
"Y", "Z"
);
List<String> flattened = deepFlatten(iterable, String.class);
System.out.println(flattened);
Gave me:
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
Note that the letters are in order because List
s and arrays have guaranteed iteration orders. If your Iterable
contained a Set
the result of the deepFlatten
may not be in the same order each time.
add a comment |
As others have mentioned, using exceptions for control flow is not ideal. You can instead use the instanceof
operator to test if an element is a Collection
. The answer by nullpointer shows a good example of this. If you want an more generic option you could also do something like:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public static <E> List<E> deepFlatten(final Iterable<?> iterable, final Class<E> type) {
if (type.isPrimitive() || type.isArray() || Iterable.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(
"type must not denote a primitive, array, or java.lang.Iterable type: " + type);
}
final List<E> result = new ArrayList<>();
for (final Object element : iterable) {
if (element instanceof Iterable<?>) {
result.addAll(deepFlatten((Iterable<?>) element, type)); // recursion
} else if (element != null && element.getClass().isArray()) {
if (element instanceof Object) {
result.addAll(deepFlatten(Arrays.asList((Object) element), type)); // recursion
} else { // primitive array
final Iterable<?> itrArray = IntStream.range(0, Array.getLength(element))
.mapToObj(index -> Array.get(element, index))::iterator; // method reference
result.addAll(deepFlatten(itrArray, type)); // recursion
}
} else {
/*
* Will throw ClassCastException if any element is not an instance
* of "type". You could also throw a NullPointerException here if
* you don't want to allow null elements.
*/
result.add(type.cast(element));
}
}
return result;
}
This also handles "embedded" arrays, as well as Iterable
s, through recursion. Note it doesn't handle Map
s because of the ambiguity; should we flatten the keys or the values—or both?
Calling the above with:
Iterable<?> iterable = List.of(
"A", "B", "C", "D",
List.of("E", "F", List.of("G", "H"), "I", "J"),
"K",
new String{"L", "M", "N", "O", "P"},
new String{{"Q", "R"}, {"S", "T"}, {"U"}, {"V"}},
new Object{"W", "X"},
"Y", "Z"
);
List<String> flattened = deepFlatten(iterable, String.class);
System.out.println(flattened);
Gave me:
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
Note that the letters are in order because List
s and arrays have guaranteed iteration orders. If your Iterable
contained a Set
the result of the deepFlatten
may not be in the same order each time.
As others have mentioned, using exceptions for control flow is not ideal. You can instead use the instanceof
operator to test if an element is a Collection
. The answer by nullpointer shows a good example of this. If you want an more generic option you could also do something like:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public static <E> List<E> deepFlatten(final Iterable<?> iterable, final Class<E> type) {
if (type.isPrimitive() || type.isArray() || Iterable.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(
"type must not denote a primitive, array, or java.lang.Iterable type: " + type);
}
final List<E> result = new ArrayList<>();
for (final Object element : iterable) {
if (element instanceof Iterable<?>) {
result.addAll(deepFlatten((Iterable<?>) element, type)); // recursion
} else if (element != null && element.getClass().isArray()) {
if (element instanceof Object) {
result.addAll(deepFlatten(Arrays.asList((Object) element), type)); // recursion
} else { // primitive array
final Iterable<?> itrArray = IntStream.range(0, Array.getLength(element))
.mapToObj(index -> Array.get(element, index))::iterator; // method reference
result.addAll(deepFlatten(itrArray, type)); // recursion
}
} else {
/*
* Will throw ClassCastException if any element is not an instance
* of "type". You could also throw a NullPointerException here if
* you don't want to allow null elements.
*/
result.add(type.cast(element));
}
}
return result;
}
This also handles "embedded" arrays, as well as Iterable
s, through recursion. Note it doesn't handle Map
s because of the ambiguity; should we flatten the keys or the values—or both?
Calling the above with:
Iterable<?> iterable = List.of(
"A", "B", "C", "D",
List.of("E", "F", List.of("G", "H"), "I", "J"),
"K",
new String{"L", "M", "N", "O", "P"},
new String{{"Q", "R"}, {"S", "T"}, {"U"}, {"V"}},
new Object{"W", "X"},
"Y", "Z"
);
List<String> flattened = deepFlatten(iterable, String.class);
System.out.println(flattened);
Gave me:
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
Note that the letters are in order because List
s and arrays have guaranteed iteration orders. If your Iterable
contained a Set
the result of the deepFlatten
may not be in the same order each time.
edited 53 mins ago
answered 1 hour ago
SlawSlaw
8,04231033
8,04231033
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54624265%2fhow-to-concatenate-lists-into-one-list%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
fyi Java does not support mixed match type in list as you have in
input
, it can be likeinput = [[1],[2],[3,4], [5,6], [7]];
– dkb
3 hours ago
and there could be
null
values there (exception handling is for what otherwise)?– nullpointer
3 hours ago
I think you can do this
concatenated.addAll((Iterable) v);
instead of try to cast to bothCollection
andList
.– MrCholo
3 hours ago
2
@MrCholo An array list does not have an overload for
addAll
withIterable
. The simplest interface you can use isCollection
See here. The reason being thatIterable
doesn't have to persist the data. It can be a read once, or even random in what data is returned. All it specifies is that you can iterate on it.– flakes
2 hours ago