Get all first value of List<Object[]> - java

how can I retrieve only the pet types using lambda expression? I want a new list containing only "dog", "cat", etc,
I have list:
List<Object[]> list;
in this list I have structure:
list.get(0) returns ("dog", 11)
list.get(1) returns ("cat", 22)
etc.
how can I retrieve only the pet types using lambda expression? I want a new list containing only "dog", "cat", etc,

An easy way is the use of the stream api:
List firstElements = list.stream().map(o -> o[0]).collect(Collectors.toList());

It is as simple as using map and collect.
private void test(String[] args) {
List<Animal> list = new ArrayList<>();
list.add(new Animal("dog",11));
list.add(new Animal("cat",22));
List<String> names = list.stream()
// Animal -> animal.type.
.map(a -> a.getType())
// Collect into a list.
.collect(Collectors.toList());
System.out.println(names);
}
I used Animal as:
class Animal {
final String type;
final int age;
public Animal(String type, int age) {
this.type = type;
this.age = age;
}
public String getType() {
return type;
}
public int getAge() {
return age;
}
#Override
public String toString() {
return "Animal{" +
"type='" + type + '\'' +
", age=" + age +
'}';
}
}

Related

Unable to get desired output in "Predicate" "and" of Java

I have the following class Person -
Person.java -
public class Person {
private int id;
private String department;
private double salary;
public Person(int id, String department, double salary) {
this.id = id;
this.department = department;
this.salary = salary;
}
public String getDepartment() {
return department;
}
public double getSalary() {
return salary;
}
#Override
public String toString() {
return "Person{" +
"id=" + id +
", department='" + department + '\'' +
", salary=" + salary +
'}';
}
}
It has the fields -
id, department, salary
Now I have first predicate -
Predicate<List<Person>> hasSalaryOf40k = list -> {
boolean myReturn = false;
Iterator<Person> iterator = list.iterator();
while (iterator.hasNext()) {
Person person = iterator.next();
double salary = person.getSalary();
if (salary == 40000) {
myReturn = true;
break;
}
}
return myReturn;
};
Here, I want to filter out those lists having persons with salary as 40K.
Second predicate -
Predicate<List<Person>> isDeveloper = list -> {
boolean myReturn = false;
Iterator<Person> iterator = list.iterator();
while (iterator.hasNext()) {
Person person = iterator.next();
String department = person.getDepartment();
if (department.equals("Developer")) {
myReturn = true;
break;
}
}
return myReturn;
};
Here, I want to filter out those lists having persons with department as 'developer'
Third predicate -
Predicate<List<Person>> hasSalaryOf40kAndIsDeveloper = list ->
hasSalaryOf40k.and(isDeveloper).test(list);
Here, I want to filter out those lists having persons with both salary as 40K and department as "developer"
Now I have the following two lists -
List<Person> list1 = new ArrayList<>(List.of(
new Person(1, "Developer", 35000),
new Person(2, "Accountant", 40000),
new Person(3, "Clerk", 20000),
new Person(4, "Manager", 50000)
));
List<Person> list2 = new ArrayList<>(List.of(
new Person(1, "Developer", 40000),
new Person(2, "Accountant", 35000),
new Person(3, "Clerk", 22000),
new Person(4, "Manager", 55000)
));
The list1 does not match the desired criteria while list2 matches the desired criteria.
Now I call the predicate method test -
System.out.println(hasSalaryOf40kAndIsDeveloper.test(list1));
System.out.println(hasSalaryOf40kAndIsDeveloper.test(list2));
Output -
true
true
Desired output -
false
true
Where am I going wrong and how to correct my code?
You're applying the predicate to the whole list and not each element of the list, so it's true that the list contains a developer and its true that the list contains a salary over 40k. You need to apply the predicate to the Person object rather than the List<Person> object

How to sort array of objects based on order of another array

I have an ArrayList of Strings in a certain particular order
ArrayList<String> sortedkeys
And I have an unordered set of objects
Set<Skugroup> unsortedSet
Where SkuGroup contains a key to be used for sorting
Class SkuGroup {
private String sortkey;
private String name;
}
I need to copy all the SkuGroup objects into a new array in the same order of sortedSkus, where the sortedkey value is the same as the SkuGroup->sortkey
How can I accomplish this?
I believe the best way would be to store the set as a TreeSet, because it keeps its elements sorted by a given comparator. To make it easier, here we can implement interface Comparable on the SkuGroup class.
class SkuGroup implements Comparable<SkuGroup> {
private String sortKey;
private String name;
public String getSortKey() {
return sortKey;
}
public int compareTo(SkuGroup s1) {
return this.sortKey.trim().compareTo(s1.getSortKey().trim());
}
}
ArrayList<String> sortedKeys = new ArrayList<>();
Set<SkuGroup> skuSet = new TreeSet<>();
/** add items to skuSet **/
I need to copy all the SkuGroup objects into a new array in the same
order of sortedSkus, where the sortedkey value is the same as the
SkuGroup->sortkey
I assume you mean you want to transfer just the sortKey, and not the entire object because of the type on the ArrayList.
skuSet.stream().forEach(item -> sortedKeys.add(item.getSortKey()));
import java.util.*;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
System.out.println("Expected order: c -> b -> a -> d");
List<String> sortedkeys = Arrays.asList("c", "b", "a", "d");
// Construct unsorted set (of course a Set has no order);
System.out.println("Unsorted order: a -> b -> c -> d");
Set<SkuGroup> unsortedSet = new HashSet<>(Arrays.asList(
new SkuGroup("a", "name_a"),
new SkuGroup("b", "name_b"),
new SkuGroup("c", "name_c"),
new SkuGroup("d", "name_d")));
List<SkuGroup> sortedSkuGroups = sortedkeys.stream()
.map(key -> unsortedSet.stream()
.filter(skuGroup -> skuGroup.getSortKey().equals(key))
.findFirst()
.get()
).collect(Collectors.toList());
System.out.println("Sorted order: " + sortedSkuGroups);
// In case if you need to convert this into Array:
SkuGroup[] sortedSkuGroupArray = sortedSkuGroups.stream().toArray(SkuGroup[]::new);
System.out.println("Sorted order in Array: " + Arrays.toString(sortedSkuGroupArray));
}
}
class SkuGroup {
private String sortKey;
private String name;
public SkuGroup(String sortKey, String name) {
this.sortKey = sortKey;
this.name = name;
}
public String getSortKey() {
return sortKey;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "{'" + sortKey + '\'' + ":'" + name + "\'}";
}
}
Result:
> Task :Test.main()
Expected order: c -> b -> a -> d
Unsorted order: a -> b -> c -> d
Sorted order: [{'c':'name_c'}, {'b':'name_b'}, {'a':'name_a'}, {'d':'name_d'}]
Sorted order in Array: [{'c':'name_c'}, {'b':'name_b'}, {'a':'name_a'}, {'d':'name_d'}]

Reduce list of object into Immutable map with lambda

I have a list of Person object. All person has a unique id, but the person's name can be the same.
Person {
String id,
String name,
}
I want to convert this array of persons into ImmutableMap<String, ImmutableSet<String>>. The key of the map should be the user's name, the immutable set contains the ids of specific user's name.
I know how to do it using HashMap and HashSet:
for (person : personList) {
String id = person.id;
String name = person.name;
if (!hashMap.containsKey(name)) {
hashMap.put(name, new HashSet<String>());
}
hashMap.get(name).add(id);
}
I want to know how to do it using ImmutableMap, ImmutableSet with lambda.
Here is one possible solution.
First, generate some data. Three names and 18 ids. Put them in a list.
Random r = new Random();
int[] ids = r.ints(1000, 1, 1000).distinct().limit(18).toArray();
int id = 0;
List<Person> people = new ArrayList<>();
for (int i = 0; i < 6; i++) {
for (String name : List.of("Bob", "Joe", "Mary")) {
people.add(new Person(name, ids[id++]));
}
}
Now creating the map.
Use groupingBy to create a key pointing to a collection. The key is the
name and the collection is the map.
The collection(a set) holds the ids
Map<String, Set<Integer>> nameToID =
Collections.unmodifiableMap(people.stream().collect(
Collectors.groupingBy(Person::getName, Collectors.mapping(
Person::getID, Collectors.toUnmodifiableSet()))));
Print them.
nameToID.entrySet().forEach(
e -> System.out.println(e.getKey() + " -> " + e.getValue()));
}
}
Here is the Person class with some additional methods and a constructor.
class Person {
String name;
int id;
public Person(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getID() {
return id;
}
public String toString() {
return "(" + name + "," + id + ")";
}
}

Sorting an arrayList based on a specific value in it with grouping [duplicate]

This question already has answers here:
Sort ArrayList of custom Objects by property
(29 answers)
Closed 6 years ago.
My code is as follows:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Sorting {
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> theMenu = new ArrayList<String>();
String[] Array1 = {
"M1", "Wine", "2.50",
"M2", "Soft drink", "1.50",
"D1", "Fish", "7.95",
"D2", "Veg chili", "6.70"
};
theMenu.addAll(Arrays.asList(Array1));
String[] temp1 = new String[3];
String[] temp2 = new String[3];
for (int i = 0; i < theMenu.size(); i+=3) {
for (int j = i + 3; j < theMenu.size(); j+=3) {
if (i < theMenu.size() - 3) {
if (theMenu.get(i).compareTo(theMenu.get(i + 3)) > 0) {
temp1[0] = theMenu.get(i);
temp1[1] = theMenu.get(i + 1);
temp1[2] = theMenu.get(i + 2);
temp2[0] = theMenu.get(j);
temp2[1] = theMenu.get(j+1);
temp2[2] = theMenu.get(j+2);
theMenu.remove(j + 2);
theMenu.remove(j + 1);
theMenu.remove(j);
theMenu.remove(i + 2);
theMenu.remove(i + 1);
theMenu.remove(i);
theMenu.add(i, temp2[0]);
theMenu.add(i + 1, temp2[1]);
theMenu.add(i + 2, temp2[2]);
theMenu.add(j, temp1[0]);
theMenu.add(j + 1, temp1[1]);
theMenu.add(j + 2, temp1[2]);
}
}
}
}
System.out.println(theMenu);
}
}
I want to sort the ArrayList in the order D1, D2, M1, M2, M3, while keeping its respective items and price WITH the IDs. I am not allowed to change the storing method i.e make another class of Items with its own ID and name and price. How can I rearrange it so that it is in the form :
{"D1" , "Fish", "7.95"
"D2" , "Veg chili", "6.70",
"M1" , "Wine", "2.50",
"M2", "Soft drink", "1.50"
}
Inside the ArrayList. This should work regardless of how many items we store inn the arrayList. My code produces the following output:
[M1, Wine, 2.50, M2, Soft drink, 1.50, D1, Fish, 7.95, D2, Veg chili, 6.70]
Note: Forget the new lines in the array, I just need the indexes sorted out. Can anyone help me with this?
Firstly, you have a entity - product, which has Id, name and price.
Always create new class for each Entity in your application.
Example:
public class MyObject implements Comparable
{
private String id;
private String name;
private double price;
public MyObject(String id, String name, double price)
{
this.id = id;
this.name = name;
this.price = price;
}
public String getId()
{
return id;
}
#Override
public int compareTo(Object o)
{
MyObject receivedObject = (MyObject) o;
return this.id.compareTo(receivedObject.getId());
}
#Override
public String toString()
{
return "MyObject{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
I use "implements Comparable" for easy write sorting. When we implement this interphace we must override
public int compareTo(Object o)
{
MyObject receivedObject = (MyObject) o;
return this.id.compareTo(receivedObject.getId());
}
This method compare 2 Objects and say which object "bigger". In your case we need compare only by Ids.
Now you have entity with ability to compare with each other. Check it:
public class Processing
{
public static void main(String[] argc) {
List<MyObject> list = new ArrayList<>();
list.add(new MyObject("M1", "Wine", 2.50));
list.add(new MyObject("M2", "Soft drink", 1.50));
list.add(new MyObject("D1", "Fish", 7.95));
list.add(new MyObject("D2", "Veg chili", 6.70));
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
First output:
MyObject{id='M1', name='Wine', price=2.5},
MyObject{id='M2', name='Soft drink', price=1.5},
MyObject{id='D1', name='Fish', price=7.95},
MyObject{id='D2', name='Veg chili', price=6.7}
Second output:
MyObject{id='D1', name='Fish', price=7.95},
MyObject{id='D2', name='Veg chili', price=6.7},
MyObject{id='M1', name='Wine', price=2.5},
MyObject{id='M2', name='Soft drink', price=1.5}

Best data structure to "group by" and aggregate values in Java?

I created an ArrayList of Array type like below,
ArrayList<Object[]> csvArray = new ArrayList<Object[]>();
As you can see, each element of the ArrayList is an array like {Country, City, Name, Age}.
Now I'm wanting to do a "group by" on Country and City (combined), followed by taking the average Age of the people for each Country+City.
May I know what is the easiest way to achieve this? Or you guys have suggestions to use data structures better than ArrayList for this "group by" and aggregation requirements?
Your answers are much appreciated.
You will get lot of options in Java 8.
Example
Stream<Person> people = Stream.of(new Person("Paul", 24), new Person("Mark",30), new Person("Will", 28));
Map<Integer, List<String>> peopleByAge = people
.collect(groupingBy(p -> p.age, mapping((Person p) -> p.name, toList())));
System.out.println(peopleByAge);
If you can use Java 8 and no specific reason for using a data structure, you can go through below tutorial
http://java.dzone.com/articles/java-8-group-collections
You could use Java 8 streams for this and Collectors.groupingBy. For example:
final List<Object[]> data = new ArrayList<>();
data.add(new Object[]{"NL", "Rotterdam", "Kees", 38});
data.add(new Object[]{"NL", "Rotterdam", "Peter", 54});
data.add(new Object[]{"NL", "Amsterdam", "Suzanne", 51});
data.add(new Object[]{"NL", "Rotterdam", "Tom", 17});
final Map<String, List<Object[]>> map = data.stream().collect(
Collectors.groupingBy(row -> row[0].toString() + ":" + row[1].toString()));
for (final Map.Entry<String, List<Object[]>> entry : map.entrySet()) {
final double average = entry.getValue().stream()
.mapToInt(row -> (int) row[3]).average().getAsDouble();
System.out.println("Average age for " + entry.getKey() + " is " + average);
}
You can check the collections recommended by #duffy356. I can give you an standard solution related with java.utils
I'd use a common Map<Key,Value> and being specific a HashMap.
For the keys, as I can see, you'll need and extra plain object which relates country and city. The point is create a working equals(Object) : boolean method. I'd use the Eclipse-auto generator; for me it gives me the following:
class CountryCityKey {
// package visibility
String country;
String city;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((country == null) ? 0 : country.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CountryCityKey other = (CountryCityKey) obj;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
return true;
}
}
Now we can group or objects in a HashMap<CountryCityKey, MySuperObject>
The code for that could be:
Map<CountryCityKey, List<MySuperObject>> group(List<MySu0perObject> list) {
Map<CountryCityKey, MySuperObject> response = new HashMap<>(list.size());
for (MySuperObject o : list) {
CountryCityKey key = o.getKey(); // I consider this done, so simply
List<MySuperObject> l;
if (response.containsKey(key)) {
l = response.get(key);
} else {
l = new ArrayList<MySuperObject>();
}
l.add(o);
response.put(key, l);
}
return response;
}
And you have it :)
you could use the brownies-collections library of magicwerk.org (http://www.magicwerk.org/page-collections-overview.html)
they offer keylists, which fit your requirements.(http://www.magicwerk.org/page-collections-examples.html)
I would recommend an additional step. You gather your data from CSV in Object[]. If you wrap your data into a class containing these data java8 collections will easily help you. (also without but it is more readable and understandable)
Here is an example - it introduces a class Information which contains your given data (country, city,name, age). The class has a constructor initializing these fields by a given Object[] array which might help you to do so - BUT: the fields have to be fixed (which is usual for CSV):
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CSVExample {
public static void main(String[] args) {
ArrayList<Information> csvArray = new ArrayList<>();
csvArray.add(new Information(new Object[] {"France", "Paris", "Pierre", 34}));
csvArray.add(new Information(new Object[] {"France", "Paris", "Madeleine", 26}));
csvArray.add(new Information(new Object[] {"France", "Toulouse", "Sam", 34}));
csvArray.add(new Information(new Object[] {"Italy", "Rom", "Paul", 44}));
// combining country and city with whitespace delimiter to use it as the map key
Map<String, List<Information>> collect = csvArray.stream().collect(Collectors.groupingBy(s -> (s.getCountry() + " " + s.getCity())));
//for each key (country and city) print the key and the average age
collect.forEach((k, v) -> System.out.println(k + " " + v.stream().collect(Collectors.averagingInt(Information::getAge))));
}
}
class Information {
private String country;
private String city;
private String name;
private int age;
public Information(Object[] information) {
this.country = (String) information[0];
this.city = (String) information[1];
this.name = (String) information[2];
this.age = (Integer) information[3];
}
public Information(String country, String city, String name, int age) {
super();
this.country = country;
this.city = city;
this.name = name;
this.age = age;
}
public String getCountry() {
return country;
}
public String getCity() {
return city;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
#Override
public String toString() {
return "Information [country=" + country + ", city=" + city + ", name=" + name + ", age=" + age + "]";
}
}
The main shows a simple output for your question.
In java 8 the idea of grouping objects in a collection based on the values of one or more of their properties is simplified by using a Collector.
First, I suggest you add a new class as follow
class Info {
private String country;
private String city;
private String name;
private int age;
public Info(String country,String city,String name,int age){
this.country=country;
this.city=city;
this.name=name;
this.age=age;
}
public String toString() {
return "("+country+","+city+","+name+","+age+")";
}
// getters and setters
}
Setting up infos
ArrayList<Info> infos =new ArrayList();
infos.add(new Info("USA", "Florida", "John", 26));
infos.add(new Info("USA", "Florida", "James", 18));
infos.add(new Info("USA", "California", "Alan", 30));
Group by Country+City:
Map<String, Map<String, List<Info>>>
groupByCountryAndCity = infos.
stream().
collect(
Collectors.
groupingBy(
Info::getCountry,
Collectors.
groupingBy(
Info::getCity
)
)
);
System.out.println(groupByCountryAndCity.get("USA").get("California"));
Output
[(USA,California,James,18), (USA,California,Alan,30)]
The average Age of the people for each Country+City:
Map<String, Map<String, Double>>
averageAgeByCountryAndCity = infos.
stream().
collect(
Collectors.
groupingBy(
Info::getCountry,
Collectors.
groupingBy(
Info::getCity,
Collectors.averagingDouble(Info::getAge)
)
)
);
System.out.println(averageAgeByCountryAndCity.get("USA").get("Florida"));
Output:
22.0
/* category , list of cars*/
Please use the below code : I have pasted it from my sample app !Happy Coding .
Map<String, List<JmCarDistance>> map = new HashMap<String, List<JmCarDistance>>();
for (JmCarDistance jmCarDistance : carDistanceArrayList) {
String key = jmCarDistance.cartype;
if(map.containsKey(key)){
List<JmCarDistance> list = map.get(key);
list.add(jmCarDistance);
}else{
List<JmCarDistance> list = new ArrayList<JmCarDistance>();
list.add(jmCarDistance);
map.put(key, list);
}
}
Best data structure is a Map<Tuple, List>.
Tuple is the key, i.e. your group by columns.
List is used to store the row data.
Once you have your data in this structure, you can iterate through each key, and perform the aggregation on the subset of data.

Categories