Combine multiple Collections into a single logical Collection?
With Guava, you can use Iterables.concat(Iterable<T> ...)
, it creates a live view of all the iterables, concatenated into one (if you change the iterables, the concatenated version also changes). Then wrap the concatenated iterable with Iterables.unmodifiableIterable(Iterable<T>)
(I hadn't seen the read-only requirement earlier).
From the Iterables.concat( .. )
JavaDocs:
Combines multiple iterables into a
single iterable. The returned iterable
has an iterator that traverses the
elements of each iterable in inputs.
The input iterators are not polled
until necessary. The returned
iterable's iterator supportsremove()
when the corresponding input iterator
supports it.
While this doesn't explicitly say that this is a live view, the last sentence implies that it is (supporting the Iterator.remove()
method only if the backing iterator supports it is not possible unless using a live view)
Sample Code:
final List<Integer> first = Lists.newArrayList(1, 2, 3);
final List<Integer> second = Lists.newArrayList(4, 5, 6);
final List<Integer> third = Lists.newArrayList(7, 8, 9);
final Iterable<Integer> all =
Iterables.unmodifiableIterable(
Iterables.concat(first, second, third));
System.out.println(all);
third.add(9999999);
System.out.println(all);
Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999]
Edit:
By Request from Damian, here's a similar method that returns a live Collection View
public final class CollectionsX {
static class JoinedCollectionView<E> implements Collection<E> {
private final Collection<? extends E>[] items;
public JoinedCollectionView(final Collection<? extends E>[] items) {
this.items = items;
}
@Override
public boolean addAll(final Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
for (final Collection<? extends E> coll : items) {
coll.clear();
}
}
@Override
public boolean contains(final Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(final Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean isEmpty() {
return !iterator().hasNext();
}
@Override
public Iterator<E> iterator() {
return Iterables.concat(items).iterator();
}
@Override
public boolean remove(final Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(final Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(final Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
int ct = 0;
for (final Collection<? extends E> coll : items) {
ct += coll.size();
}
return ct;
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public <T> T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
}
/**
* Returns a live aggregated collection view of the collections passed in.
* <p>
* All methods except {@link Collection#size()}, {@link Collection#clear()},
* {@link Collection#isEmpty()} and {@link Iterable#iterator()}
* throw {@link UnsupportedOperationException} in the returned Collection.
* <p>
* None of the above methods is thread safe (nor would there be an easy way
* of making them).
*/
public static <T> Collection<T> combine(
final Collection<? extends T>... items) {
return new JoinedCollectionView<T>(items);
}
private CollectionsX() {
}
}
Merge several CollectionsA into a single CollectionA from a CollectionB using Guava
You can use a function to extract the list and concat to flatten the lists. This results in an Iterable.
List<A> input;
Function<A, List<B>> t = new Function<A, List<B>>() {
@Override public List<B> apply(A input) {
return input.myListOfB;
}
};
Iterable<B> transform = Iterables.concat(Iterables.transform(input, t));
You can create an List if you need it:
ImmutableList<B> asList = ImmutableList.copyOf(transform);
//or
List<B> newArrayList = Lists.newArrayList(transform);
Note: Normally, public fields of classes are static and immutable or private. Everything else will bring you in trouble.
How to flatten the structure of multiple collections into a single one with a common id with streams
If I understand correctly, you want to do:
public List<ListDetails> groupListWithProductsById1(List<ListWithDetailsRow> listWithDetailsRows) {
return listWithDetailsRows.stream()
.collect(Collectors.groupingBy(ListWithDetailsRow::getListId)).values().stream()
.map(rows ->
new ListDetails(
rows.get(0).getName(),
rows.get(0).getListId(),
rows.get(0).getCustomerId(),
rows.get(0).getCreatedAt(),
rows.get(0).getUpdatedAt(),
rows.stream().map(row -> new ListProductDetails(
row.getProductId(), row.getQuantity(), row.getAddedAt()
)).collect(Collectors.toList())
)
).collect(Collectors.toList());
}
After grouping by the list ID, you have a Collection<List<ListWithDetailsRow>>
as the values()
of the returned map. Each of the lists in the collection represents a group.
You can then map
each group to a ListDetails
. The name
, listId
, customerId
, createdAt
and updatedAt
fields of the ListDetails
can be taken from an arbitrary element in the group (I've chosen the first one), since every element should have the same values for those fields.
For the products
field, just map
the ListWithDetailsRow
s to ListProductDetails
and collect to a list.
Create a single collection from multiple collections in a way that maximises distance between elements of the same initial collection
You can flatten values using zipWithIndex
to combine them with index inside every group then group by that index and flatten again:
grouped.values
.flatMap(xs => xs.zipWithIndex)
.groupBy(_._2)
.values
.flatMap(_.unzip._1)
How do I merge two different collections of same database into a new collection having similar field values in MongoDB?
the real problem was type casting. I failed to notice that unitId was a number(int32) but Unitid was a string, because of this aggregation operation was not carried out. Mongodb community forum helped me to realize such a trivial mistake. Here is the link to that. The code with type conversion is as follows:
[
{
'$addFields': {
'unitId': {
'$toString': '$unitId'
}
}
}, {
'$lookup': {
'from': 'datas',
'localField': 'unitId',
'foreignField': 'elevatorInfo.Institution_Characteristics.Unitid',
'as': 'nice'
}
}, {
'$unwind': {
'path': '$nice'
}
}, {
'$project': {
'__v': 0,
'_id': 0
}
}
]
Mapstruct - mapping from multiple collections into a single collection
So I would make a mapping from my SourceObject
(not write List<UserNumber> listsToDtoList(List<PhoneNumber> phoneNumbers, List<FaxNumber> faxNumbers);
So something along the lines:
@Mapping( target = "userNumbers", source = "phoneNumbers" )
Target map( Source source );
@AfterMapping // will be applied in the final part of the previous method
default void map ( Source source, @MappingTarget Target target ) {
target.getUserNumbers().addAll(source.getFaxNumbers());
}
Related Topics
How to Enumerate All Classes in a Package and Add Them to a List
Date Format Parse Exception - "Eee Mmm Dd Hh:Mm:Ss Z Yyyy"
Differencebetween Class.This and This in Java
Gradle: Could Not Determine Java Version from '11.0.2'
How to Read the Manifest File for a Webapp Running in Apache Tomcat
How to Use @Id with String Type in JPA/Hibernate
In Log4J, Does Checking Isdebugenabled Before Logging Improve Performance
Returning Overlapping Regular Expressions
Why Do We Assign a Parent Reference to the Child Object in Java
Flutter Doctor --Android-Licenses Gives a Java Error
Final Keyword in Method Parameters
Why Does Eclipse Complain About @Override on Interface Methods