Genarate list of objects in test using spock - java

I am writing a spock test, wherein I need to generate some test data (Fixtures). I know how it could be done in Java, but failing to get it implemented in spock(groovy).
I'm new to groovy, hence I'm providing my java implementation
Java implementation as follows :
List<Employee> employees= LongStream.range(1, 70).mapToObj(id -> {
Employee emp = new Employee ();
emp.setEmployeeId(id);
return emp ;
}).collect(Collectors.toList());
I'm trying to achieve the same using groovy, but unable to get it right.
def employees = [1..70].each { id ->
def emp = new Employee()
emp.setEmployeeId(id)
employees << emp
}
Appraciate any help to fix the groovy code..

[1..70] creates a list with one element that is a range. You want to use something like (1..70):
(1..70).each{employees << new Employee(employeeId: it)}
Just a side note: you can avoid appending to the list by just creating one using collect:
List<Employee> employees = (1..70).collect{new Employee(employeeId: it)}

Related

Get all elements in flat format from nested set structure

I need to get the data back similar to flatMap but it is not working in some scenario. Following are the details. Below is the pseudo code
class Employee {
String name;
int age;
}
Employee emp1 = new Employee("Peter",30);
Employee emp2 = new Employee("Bob",25);
Set<Employee> empSet1 = new HashSet();
empSet1.add(emp1);
empSet1.add(emp2);
Employee emp3 = new Employee("Jack",31);
Employee emp4 = new Employee("Laura",27);
Set<Employee> empSet2 = new HashSet();
empSet2.add(emp3);
empSet2.add(emp4);
Map<String,Set<Employee>> empLocationMap = new HashMap();
empLocationMap.put("location1",empSet1);
empLocationMap.put("location2",empSet2);
Set<Employee> empSet = getEmployeeSetForLocation("location1",empLocationMap);
private static Set getEmployeeSetForLocation(String location,Map<String,Set<Employee>> locationEmpMap) {
Object filteredObject = locationMap.entrySet().stream().filter(element-> element.getKey().equals(location)).flatMap(element-> Stream.of(element)).collect(Collectors.toSet());
return new HashSet(filteredObject );
}
The filteredObject in the method getEmployeeSetForLocation on inspection shows containing 1 element and that element is of type Set containing 2 elements. I want to know, what modification can I make in the above logic to flatten the structure further so that filteredObject shows a set with 2 elements. Any pointers will be helpful. I am using Java 8.
Regards
Use flatMap, mapping the stream of MapEntry to stream of Employee
Set<Employee> filteredObject = locationMap.entrySet().stream()
-- Here you have stream of Map.Entry, where value is employee
.filter(element -> element.getKey().equals(location))
-- And here is how to convert this stream to Stream<Employee>
.flatMap(s -> s.getValue().stream())
.collect(Collectors.toSet());
Use Set::stream) in .flatMap():
Object filteredObject = locationMap.entrySet().stream()
.filter(entry -> entry.getKey().equals(location))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
You already organized your employees by location in a map. Why are you going to the trouble to stream and filter the map when you already have access to the employees per location in the location map? Why not just do the following:
Set<Employee> set = empLocationMap.get("location1");
It gives the exact same result had you done the streaming and filtering. And since location is being used as a key you can only have one set of employees per location anyway.

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

filter KeyValueGrouped Dataset in spark

I have a typed dataset of a custom class and use groupbykey method on it. You know that it results a KeyValueGroupedDataset. I want to filter this new dataset but there is no filter method for this type of dataset. So, My question is: How can I filter on this type of dataset? (Java solution is needed. spark version: 2.3.1).
sampleData:
"id":1,"fname":"Gale","lname":"Willmett","email":"gwillmett0#nhs.uk","gender":"Female"
"id":2,"fname":"Chantalle","lname":"Wilcher","email":"cwilcher1#blinklist.com","gender":"Female"
"id":3,"fname":"Polly","lname":"Grandisson","email":"pgrandisson2#linkedin.com","gender":"Female"
"id":3,"fname":"Moshe","lname":"Pink","email":"mpink3#twitter.com","gender":"Male"
"id":2,"fname":"Yorke","lname":"Ginnelly","email":"yginnelly4#apple.com","gender":"Male"
And What I did:
Dataset<Person> peopleDS = spark.read().format("parquet").load("\path").as(Encoders.bean(Person.class));
KeyValueGroupedDataset<String, Person> KVDS = peopleDS.groupByKey( (MapFunction<Person, String> ) f -> f.getGender() , Encoders.STRING());
//How Can I filter on KVDS's id field?
Update1 (use of flatMapGroups):
Dataset<Person> persons = KVDS.flatMapGroups((FlatMapGroupsFunction <String,Person,Person>) (f,k) -> (Iterator<Person>) k , Encoders.bean(Person.class));
Update2 (use of MapGroups)
Dataset<Person> peopleMap = KVDS.mapGroups((MapGroupsFunction <String,Person,Person>) (f,g) -> {
while (g.hasNext()) {
//What can I do here?
}
},Encoders.bean(Person.Class);
Update3 : I want to filter those groups that distinct of their ids is greater than 1. for example in below picture: I want just Female groups because distinct of their ids is greater that 1 (first field is id. Others are fname,lname,email and gender).
Update4: I did What I want with "RDD", but I want to do exactly this part of code with "Dataset":
List<Tuple2<String, Iterable<Person>>> f = PersonRDD
.mapToPair(s -> new Tuple2<>(s.getGender(), s)).groupByKey()
.filter(t -> ((Collection<Person>) t._2()).stream().mapToInt(e -> e.getId).distinct().count() > 1)
.collect();
Why don't you filter on id before grouping ? GroupByKey is an expensive action, it should be faster to filter first.
If you really want to group first, you may have to then use .flatMapGroups with identity function.
Not sure about java code but scala version would be something as follow:
peopleDS
.groupByKey(_.gender)
.mapGroups { case (gender, persons) => persons.filter(your condition) }
But again, you should filter first :). Specially since your ID field is already available before grouping.
Grouping is used for aggregation functions, you can find functions like "agg" in "KeyValueGroupedDataset" class. If you apply aggregation function for ex. "count", you will get "Dataset", and "filter" function will be available.
"groupBy" without aggregation function looks strange, other function, for ex. "distinct" can be used.
Filtering example with "FlatMapGroupsFunction":
.flatMapGroups(
(FlatMapGroupsFunction<String, Person, Person>) (f, k) -> {
List<Person> result = new ArrayList<>();
while (k.hasNext()) {
Person value = k.next();
// filter condition here
if (value != null) {
result.add(value);
}
}
return result.iterator();
},
Encoders.bean(Person.class))

Multiple conditions to filter a result set using Java 8

I am looking for some help in converting some code I have to use the really nifty Java 8 Stream library. Essentially I have a bunch of student objects and I would like to get back a list of filtered objects as seen below:
List<Integer> classRoomList;
Set<ScienceStudent> filteredStudents = new HashSet<>();
//Return only 5 students in the end
int limit = 5;
for (MathStudent s : mathStudents)
{
// Get the scienceStudent with the same id as the math student
ScienceStudent ss = scienceStudents.get(s.getId());
if (classRoomList.contains(ss.getClassroomId()))
{
if (!exclusionStudents.contains(ss))
{
if (limit > 0)
{
filteredStudents.add(ss);
limit--;
}
}
}
}
Of course the above is a super contrived example I made up for the sake of learning more Java 8. Assume all students are extended from a Student object with studentId and classRoomId. An additional requirement I would require is the have the result be an Immutable set.
A quite literal translation (and the required classes to play around)
interface ScienceStudent {
String getClassroomId();
}
interface MathStudent {
String getId();
}
Set<ScienceStudent> filter(
Collection<MathStudent> mathStudents,
Map<String, ScienceStudent> scienceStudents,
Set<ScienceStudent> exclusionStudents,
List<String> classRoomList) {
return mathStudents.stream()
.map(s -> scienceStudents.get(s.getId()))
.filter(ss -> classRoomList.contains(ss.getClassroomId()))
.filter(ss -> !exclusionStudents.contains(ss))
.limit(5)
.collect(Collectors.toSet());
}
Multiple conditions to filter really just translate into multiple .filter calls or a combined big filter like ss -> classRoomList.contains(ss.getClassroomId()) && !exclusion...
Regarding immutable set: You best wrap that around the result manually because collect expects a mutable collection that can be filled from the stream and returned once finished. I don't see an easy way to do that directly with streams.
The null paranoid version
return mathStudents.stream().filter(Objects::nonNull) // math students could be null
.map(MathStudent::getId).filter(Objects::nonNull) // their id could be null
.map(scienceStudents::get).filter(Objects::nonNull) // and the mapped science student
.filter(ss -> classRoomList.contains(ss.getClassroomId()))
.filter(ss -> !exclusionStudents.contains(ss))
.limit(5)
.collect(Collectors.toSet());

Find intersection between collections with different objects

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))));

Categories

Resources