Find intersection between collections with different objects - java

I have list of custom objects like below:
List<CustomObject> existingValues
And another collection with ids that has been sent from client and contains ids of CustomObject mentoioned above Set<Long> ids.
My goal is to return collection with CustomObject that will contains only elements where ids intersect.
I can simply do this with nested for each cycles. But it looks a bit ugly.
In SQL I can do similar stuff with query:
select * where customobject.id in (some ids...)
In wich way it can be achived with lamdaj or guava?

With Guava this is done as follows:
final Set<Long> ids = ...; //initialize correctly
List<CustomObject> results = FluentIterable.from(existingValues).filter(new Predicate<CustomObject>() {
#Override
public boolean apply(final CustomObject input) {
return ids.contains(input.getId());
}
}).toList();

With Java 8 you can achieve this with a stream filter:
List<CustomObject> collect = existingValues.stream()
.filter(object -> ids.contains(object.getId()))
.collect(Collectors.toList());
To get familiar with java streams I recommand the offical Oracle Tutorial.

Yes as #wuethrich44 says in Java 8 the solution is:
List<CustomObject> collect = existingValues.stream()
.filter(object -> ids.contains(object.getId()))
.collect(Collectors.toList());
And in the case you have a version older than Java 8:
List<CustomObject> collect = new ArrayList<CustomObject>();
for(CustomObject object: existingValues) {
if(ids.contains(object.getId())) {
collect.add(object);
}
}
And for version older than Java 5:
List<CustomObject> collect = new ArrayList<CustomObject>();
Iterator<CustomObject> iterator = existingValues.iterator();
while(iterator.hasNext()) {
CustomObject object = iterator.next();
if(ids.contains(object.getId())) {
collect.add(object);
}
}
but the version with stream is better: faster in term of execution time, less verbose, and more readable if you are use to it

If you can use my xpresso library you can use list comprehensions with lambda expressions like this:
list<CustomObject> filtered = x.list(x.<CustomObject>yield().forEach(existingValues).when(x.lambdaP("x : f1(f0(x))",x.invoke("getId"),x.in(ids))));

Related

Consume the results of Neo4j driver in java

Using Neo4j driver for java, i want to send a search query to the database such as:
MATCH(a:`Label`{Property:"NODE_PROPERTY"})
RETURN *
First i create a session and the i use the run methods of the driver to run a query:
Result run = session.run(query);
run variable contains a list of Records. My question is how can i consume the records so that i can convert them to java objects? I tried to get the values of the results but since they're not iterable, it's not possible to get them one by one.
Result implements Iterator<Record>, so there is a bunch of ways of consuming it, e.g.:
While loop (Java 6 style):
Result result = session.run(query);
List<MyPojo> myList = new ArrayList<>();
while(result.hasNext()) {
Record r = result.next();
myList.add(mapToMyPojo(r));
}
Stream (Java 8+ style):
Result result = session.run(query);
List<MyPojo> myList = result.stream()
.map(record -> mapToMyPojo(record))
.collect(Collectors.toList());
Using Result.list(Function<Record,T> mapFunction):
Result result = session.run(query);
List<MyPojo> myList = result.list(r -> mapToMyPojo(r));
Mapping to a Java object is pretty stright-forward:
public MyPojo mapToMyPojo(Record record) {
MyPojo pojo = new MyPojo();
pojo.setProperty(record.get("Property").asString());
// ...
return pojo;
}
Although instead of mapping results manually, you might want to use neo4j-ogm

Incompatible types in stream Collectors.toList() in java

I'm implementing graph representation.
Map<V, List<E<V>>> g = new HashMap<>();
one of methods in Graph class is
List<E<V>> getAllEdges() {
List<E<V>> allEdges = new ArrayList<>();
for(Map.Entry<V, List<E<V>>> entry: g.entrySet()) {
allEdges.addAll(entry.getValue());
}
return allEdges;
}
But I'd like to make it shorter line using
List<E<V>> getAllEdges() {
return g.values().stream().collect(Collectors.toList());
}
but I have an error such that
Is there a way to use stream for this?
Since your values are already typed as List<E<V>, using .collect(Collectors.toList()) is appropriate if you want to build a List<List<E<V>>.
To fix it, flatten the 2D list using flatMap:
List<E<V>> getAllEdges() {
return g.values().stream().flatMap(List::stream).collect(Collectors.toList());
}

Java 6 guava Predicate to Java 8 Predicate & Lambda

I have been developing in Java 6 and using guava predicates. But I want to switch to Java 8 and use java util predicates instead. I can simply convert the below method to use the predicate but is there a smart way to use Lambda expressions and reduce the number of lines of code ? Preferably remove the temp list I am creating ? I am googling for examples but all of them are very simple ones. Thanks for you help!
private Predicate<Objt1> getLocalAttributesPredicate() {
return new Predicate<Objt1>() {
#Override
public boolean apply(Objt1 input) {
AttributeType attr = cache.get(input.getAttributeID());
List<String> attrGroupids = Lists.newArrayList();
for (AttributeGroupLinkType group : attr.getAttributeGroupLink()) {
attrGroupids.add(group.getAttributeGroupID());
}
return attrGroupids.contains(localAttrGroupId) && !attrGroupids.contains(exclustionAttrGroupId);
}
};
}
Something like the following:
private Predicate<Objt1> getLocalAttributesPredicate() {
return input -> cache.get(input.getAttributeID())
.stream()
.map(group -> group.getAttributeGroupID())
.filter(id -> id.equals(localAttrGroupId))
.filter(id -> !id.equals(exclustionAttrGroupId))
.limit(1)
.count() > 0;
}
So the predicate is returned as a lambda function, and it utilises the Stream API to traverse the list and convert its contents.
Edit: applied the optimisation suggested by #Aominè, thanks.
This is how you'd do it as of Java-8:
private Predicate<Objt1> getLocalAttributesPredicate() {
return input -> {
Set<String> accumulator = ...
AttributeType attr = cache.get(input.getAttributeID());
for(AttributeGroupLinkType group : attr.getAttributeGroupLink())
accumulator.add(group.getAttributeGroupID());
return accumulator.contains(localAttrGroupId) &&
!accumulator.contains(exclustionAttrGroupId);
};
}
Note, that I've also used a Set for the accumulator as the Contains method is much faster for a Set implementation than for a List implementation.

how to use filter using containsAll and contains in javapairrdd

I have 2 collections one is 'list' and another 'pairRdd2' which contains data as mentioned below.
I am trying to apply filter with containsAll where in if mypairRdd2 contains all the values mentioned in list. Expected result is joe,{US,UK}
List<String> list = Arrays.asList("US","UK");
JavaRDD pairRdd = ctx.parallelize(Arrays.asList(new Tuple2("john","US"),new Tuple2("john","UAE"),new Tuple2("joe","US"),new Tuple2("joe","UK")));
JavaPairRDD<String, String> pairRdd2 = JavaPairRDD.fromJavaRDD(pairRdd);
pairRdd2.groupByKey().filter(x-> Arrays.asList(x._2).containsAll(list)).foreach(new VoidFunction<Tuple2<String,Iterable<String>>>() {
#Override
public void call(Tuple2<String, Iterable<String>> t) throws Exception {
System.out.println(t._1());
}
});
Can someone highlight what am i doing wrong...
The problem is with Arrays.asList(). This creates a list of Iterables, which is not what you need to perform the filter. You should use the list given by groupBy itself:
pairRdd2.groupByKey().filter(f -> {
Set<String> set = new HashSet<>();
for(String s: f._2())
set.add(s);
return list.containsAll(set);
});
You may also find a quick way to convert an iterable/iterator to a collection and avoid the loop altogether.

Iterate through collection, perform action on each item and return as List

Is there any way to do it with java 8 Stream API?
I need to transform each item of collection to other type (dto mapping) and return all set as a list...
Something like
Collection<OriginObject> from = response.getContent();
DtoMapper dto = new DtoMapper();
List<DestObject> to = from.stream().forEach(item -> dto.map(item)).collect(Collectors.toList());
public class DtoMapper {
public DestObject map (OriginObject object) {
return //conversion;
}
}
Thank you in advance
Update #1: the only stream object is response.getContent()
I think you're after the following:
List<SomeObject> result = response.getContent()
.stream()
.map(dto::map)
.collect(Collectors.toList());
// do something with result if you need.
Note that forEach is a terminal operation. You should use it if you want to do something with each object (such as print it). If you want to continue the chain of calls, perhaps further filtering, or collecting into a list, you should use map.

Categories

Resources