Related
say I have an array List of type Order Details
private static List<OrderDetails> orderDetails = new ArrayList<OrderDetails>();
and the fields in orderDetails are
private String productCode = null;
private int revenue = 0;
my arrayList contains the values`
A012 69
A012 36
I need to change the output of the list so that if something is added to the list of the same productCode the revenues get added together
so the output of the example above would be
A012 105
how will the method work
This should work assuming you have the appropriate getters for the class. It just creates a stream of OrderDetails objects, filters out null productCodes and creates a map of the revenue sums.
Map<String,Integer> results = orderDetails.stream()
.filter(od->od.getProductCode() != null)
.collect(Collectors.groupingBy(OrderDetails::getProductCode,
Collectors.summingInt(OrderDetails::getRevenue)));
If desired, you can then return the values back to a list by creating a new instance of each OrderDetails class.
orderDetails = results.entrySet().stream()
.map(e->new OrderDetails(e.getKey(), e.getValue()))
.collect(Collectors.toList());
Using a map might be more useful since you can get the revenue for any product code.
For example
System.out.println(results.get("A012"));
The small code snippet by using a Map as below may be helpful:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
private static List<OrderDetails> orderDetails = new ArrayList<OrderDetails>();
public static void main(String[] args) {
final OrderDetails o1 = new OrderDetails("A12", 69);
final OrderDetails o2 = new OrderDetails("A12", 36);
final OrderDetails o3 = new OrderDetails("A13", 136);
addToList(o1);
addToList(o2);
addToList(o3);
orderDetails.stream().map(orderDetail -> orderDetail.getProductCode() + " " + orderDetail.getRevenue()).forEach(System.out::println);
}
private static synchronized void addToList(OrderDetails orderDet) {
final Map<String, OrderDetails> map = orderDetails.stream().collect(Collectors.toMap(OrderDetails::getProductCode, orderDetail -> orderDetail, (a, b) -> b));
final OrderDetails objectFromMap = map.get(orderDet.getProductCode());
if (objectFromMap != null) {
objectFromMap.setRevenue(objectFromMap.getRevenue() + orderDet.getRevenue());
} else {
map.put(orderDet.getProductCode(), orderDet);
}
orderDetails.clear();
orderDetails.addAll(map.values());
}
}
class OrderDetails {
private String productCode = null;
private int revenue = 0;
public OrderDetails(String productCode, int revenue) {
this.productCode = productCode;
this.revenue = revenue;
}
public String getProductCode() {
return productCode;
}
public int getRevenue() {
return revenue;
}
public void setRevenue(int revenue) {
this.revenue = revenue;
}
}
You can use a Map like this:
Map<String, Integer> orderDetails = new new HashMap<>();
and use this method for adding a new order:
void addOrder(Order orderToAdd) {
Order findOrder = orderDetails.get(orderToAdd.productCode);
if (findOrder != null) {
findOrder.revenue += orderToAdd.revenue ;
} else {
orderDetails.put(orderToAdd.productCode, orderToAdd.revenue );
}
}
I do use strust-json library for converting java object to json automatically. The task is to provide the following output from the server to client:
{
"results":
{
"id": 1,
"text": "Option 1"
},
{
"id": 2,
"text": "Option 2"
}
}
I've created object with array properties:
public class ResultsOrganisationUnit {
private Integer[] id = new Integer[100];
private String[] text = new String[100];
public Integer[] getId() {
return id;
}
public void setId(Integer[] id) {
this.id = id;
}
public String[] getText() {
return text;
}
public void setText(String[] text) {
this.text = text;
}
}
Initialized it:
results = new ResultsOrganisationUnit();
and then later I tried to fill it out using for-each cycle:
for (OrganisationUnitNameHistory children : children2){
results.setId(new Integer[] {children.getOrganisationunitCode()});
results.setText(new String[] {children.getName()});
}
The thing is, I only get the last value of array in the output from client side.
{"results":{"id":[3509],"text":["text 1"]}}
However, the object children for example has all 5 values. It seems like I'm overriding the same array value each time, instead of filling out the new one. I'm confused where is that logical error, which I'm making. It must be something simple..
You should wrap id and text into new class, and store collection of them inside result:
public class OrganisationUnit {
private Integer id;
private String text;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
public class Results {
private List<OrganisationUnit> results = new ArrayList<>();
public List<OrganisationUnit> getResults() {
return results;
}
public void setResults(List<OrganisationUnit> results) {
this.results = results;
}
}
Fill it using loop:
Results results = new Results();
for (OrganisationUnitNameHistory children : children2) {
OrganisationUnit ou = new OrganisationUnit();
ou.setId(children.getOrganisationunitCode());
ou.setText(children.getName());
results.getResults().add(ou);
}
Or directly without using Result class:
List<OrganisationUnit> results = new ArrayList<>();
for (OrganisationUnitNameHistory children : children2) {
OrganisationUnit ou = new OrganisationUnit();
ou.setId(children.getOrganisationunitCode());
ou.setText(children.getName());
results.add(ou);
}
You are getting the last value, because that is what you ask your code to do.
I am not sure what kind of variabel the children2 is, but lets say its a List<ResultsOrganisationUnit> then one solution would be to:
private Integer[] ids = new Integer[100];
private String[] texts = new String[100];
for ( int i=0; i < children2.size(); i++) {
ids[i] = children2[i].getOrganisationunitCode();
texts[i] = children2[i].getName();
}
results.setId(ids);
results.setText(texts);
But still the task as you are referring to is not accomplished by your code.
What you will be looking at is something similar to the following, depending on the values you provide:
{
"results":
{
"id":[1, 2, 3],
"text":["text 1", "text 2", "text 3"]
}
}
To be able to get what you are asking for in the comment is to create your OrganisationUnit like this:
public class OrganisationUnit{
private Integer id;
private String text;
public Integer getId(){return id;}
public void setId(Integer id){this.id = id;}
public String getText(){return text;}
public void setText(String text){this.text = text;}
}
And then store the values for the results in a List<OrganisationUnit>
List<OrganisationUnit> results = new ArrayList();
for (OrganisationUnitNameHistory child : children2) {
OrganisationUnit tempChild = new OrganisationUnit();
tempChild.setId(child.getOrganisationunitCode());
tempChild.setText(child.getName());
results.add(tempChild);
}
The results that you return should be according what you are looking for in the comment field.
The structure of your json does not follow the pattern, since results, so you left it look like, should be an array.
See that https://www.json.org/.
What could be done would be the following structure:
{
results:
[
{"id": 1, "text": "Option 1"},
{"id": 2, "text": "Option 2"}
]
}
You need to put in your array a value, however you are always updating your references to a new array:
...
private Integer[] id = new Integer [100];
...
public void setId(Integer[] id){
// here you are adding the reference to a new array, overwriting your id reference to which you started with a new Integer[100]
this.id = id;
}
In order for the array to store the ids you may need a new property to store the current position. And your setId should get a reference to an Integer instead of an Integers Array, and add to this array the value.
private Integer[] id = new Integer[100];
private int nextPosition = 0;
...
// I omit the treatment here so that it does not add a position beyond what its array allows for simplification purposes.
public void setId(Integer[] id) {
this.id[nextPosition] = id;
nextPosition = nextPosition + 1;
}
...
So you would persist more values, but from what I understood is not exactly what you need, since the structure of the outcome would continue to be the same for which you are complaining:
// No association between ids and texts
{
"results":
{
"id": [3509, 8987, 1234, 777, 987],
"text": ["text 1", "text 2", "text 3"]
}
}
Note that results is an array of a complex object, not a Value Object such as String and Integer. Perhaps the ideal would be you to create a new object to behave and associate the id and text properties.
public class ResultsOrganisationChild {
private Integer id;
private String text;
public ResultsOrganisationChild(Integer id, String text){
this.id = id;
this.text = text;
}
// add some gets and sets
}
Optionally, you could use a List instead of an array, because then you will not have to worry about your object growing beyond what you might have initially foreseen, besides not having to worry about the next position:
public class ResultsOrganisationUnit {
private List<ResultsOrganisationChild> list = new ArrayList<>();
public void addChild(ResultsOrganisationChild child) {
list.add(child);
}
public List<ResultsOrganisationChild> getChild() {
return this.list;
}
}
Your for-each would look like this:
ResultsOrganisationUnit results = new ResultsOrganisationUnit();
for(OrganizationUnitNameHistory children: children2) {
ResultsOrganisationChild child = new ResultsOrganisationChild (children.getOrganisationunitCode(), children.getName());
results.addChild(child);
}
I have an array of object, which is basically an Arraylist.
The input and output data look like this
data= [
{
id:1,
parent:0
},
{
id:2,
parent:0
},
{
id:3,
parent:1
},
{
id:4,
parent:1
},
{
id:5,
parent:3
},
{
id:6,
parent:3
}
]
if parent of any object is equal to id, then that will become the children the result should look like this.
[
{
id:1,
parent:0,
children:[
{
id:3,
parent:1,
children:[ {
id:5,
parent:3
},
{
id:6,
parent:3
}
]
},
{
id:4,
parent:1
}
]
},
{
id:2,
parent:0
}
]
Because i am not able to access the inner element of the array of object by using for loop, i am not able to put condition on it.
i try using something like this
for(Map <String,Object> individual_object: data) {
}
How to do this?
My complete code:
try {
taxonDao.openCurrentSession();
List<Object[]> taxonList = taxonDao.list(parent, classificationId, taxonIds, expand_taxon);
List res = new ArrayList();
Map<String, Object> m1 = new HashMap<String, Object>();
TaxonUI ui = new TaxonUI();
Map<Long, Map<String, Object>> m2 = new HashMap<Long, Map<String, Object>>();
for (Object[] t : taxonList) {
Map<String, Object> m = new HashMap<String, Object>();
ui.setId((Long) t[0]);
ui.setTaxonid((Long) t[0]);
ui.setClassification((Long) t[4]);
ui.setPath((String) t[3]);
ui.setText((String) t[1]);
ui.setRank((Integer) t[2]);
if(t[5]!=null){
ui.setParent((Long)t[5]);
}
m.put("id", ui.getId());
m.put("taxonid", ui.getId());
m.put("text", ui.getText());
m.put("rank", ui.getRank());
m.put("path", ui.getPath());
m.put("classification", ui.getClassification());
m.put("parent", ui.getParent());
res.add(m);
}
return res;
} catch (Exception e) {
throw e;
} finally {
taxonDao.closeCurrentSession();
}
First you need an Item class to store the id and parent id:
(The toString() is for debugging so you can print the input and output list to verify the result)
public class Item {
private final int parentId;
private final int id;
private final java.util.List<Item> children = new ArrayList<>();
public Item(int parentId, int id) {
this.parentId = parentId;
this.id = id;
}
public void addChild(Item child) {
children.add(child);
}
#Override
public String toString() {
String result = "id: " + id + ", parent: " + parentId;
if (children.isEmpty() == false) {
result += ", children: " + children;
}
return result;
}
public int getId() {
return id;
}
public int getParentId() {
return parentId;
}
}
Then as usual, a Main class and main method to prepare the input and process it:
public class Main {
public static void main(String[] args) {
java.util.List<Item> inputItems = createInputItems();
java.util.List<Item> oututItems = processItemsToParentChildren(inputItems);
System.out.println(oututItems);
}
The create input method is straight forward:
private static List<Item> createInputItems() {
java.util.List<Item> result = new ArrayList<>();
result.add(new Item(0, 1));
result.add(new Item(0, 2));
result.add(new Item(1, 3));
result.add(new Item(1, 4));
result.add(new Item(3, 5));
result.add(new Item(3, 6));
return result;
}
Then you need a method to map id to the corresponding item:
private static Map<Integer, Item> prepareIdItemMap(List<Item> items) {
HashMap<Integer, Item> result = new HashMap<>();
for (Item eachItem : items) {
result.put(Integer.valueOf(eachItem.getId()), eachItem);
}
return result;
}
And then the critical part, to add the correct child items to their parent, or to root of the list if parent id is 0:
private static List<Item> processItemsToParentChildren(List<Item> items) {
java.util.List<Item> result = new ArrayList<>();
Map<Integer, Item> idItemMap = prepareIdItemMap(items);
for (Item eachItem : items) {
int parentId = eachItem.getParentId();
if (parentId == 0) {
result.add(eachItem);
} else {
idItemMap.get(Integer.valueOf(parentId)).addChild(eachItem);
}
}
return result;
}
Why not define a Class with the following fields (Let's define this class name as ParentChildClass:
public class ParentChildClass{
int id;
ParentChildClass parent;
ArrayList<ParentChildClass> children;
ParentChildClass(ParentChildClass parent){
this.children = new ArrayList<ParentChildClass>();
if(parent != null){
this.parent = parent;
}
}
//getter and setters
//method to add a child
public void addChild(ParentChildClass child){
children.add(child);
}
}
Now wrap this inside a HashMap<Integer, ParentChildClass> to easily access all the elements by their ids. Iterate through the object you currently have and start adding these elements one by one in the HashMap by creating instances of ParentChildClass. If the parent is already not present in the HashMap, find the element with parent's id, include it in the HashMap by creating its new instance (Don't add the parent recursively now, as you'll anyway come later to this element while iterating, when you can add the parent for this object as well). After doing this, set this newly created parent element as the parent of the Child element, and proceed.
In the end, you'll be left with a map that has references to all the parent child objects which can be used to access and element in O(1), its parent and all its children (in the arraylist).
You can connect elements to their parents by first looping them through and collecting their IDs to a map. This will allow you to then find a parent for each element after you loop them through again to construct the hierarchy that you described. Note that you also need to collect to elements without parents (called roots below.
List<MyElement> list = asList(
new MyElement(1, 0),
new MyElement(2, 0),
new MyElement(3, 1),
new MyElement(4, 1),
new MyElement(5, 3),
new MyElement(6, 3));
Map<Integer, MyElement> elementsById = new HashMap<>();
for (MyElement element : list) {
elementsById.put(element.getId(), element);
}
List<MyElement> roots = new ArrayList<>();
for (MyElement element : elementsById.values()) {
if (elementsById.containsKey(element.getParent())) {
MyElement parent = elementsById.get(element.getParent());
parent.addChild(element);
} else {
roots.add(element);
}
}
System.out.println(roots);
MyElement class for reference
public class MyElement {
private int id;
private int parent;
private List<MyElement> children = new ArrayList<>();
public MyElement(int id, int parent) {
this.id = id;
this.parent = parent;
}
#Override
public String toString() {
return "{id=" + id + ", children=" + children + "}";
}
public void addChild(MyElement child) {
if (child.parent != id) {
throw new IllegalArgumentException("Expected parent id " + id + " got " + child.parent);
}
children.add(child);
}
public int getId() {
return id;
}
public int getParent() {
return parent;
}
public List<MyElement> getChildren() {
return Collections.unmodifiableList(children);
}
}
If the inner fields of your object is private, you cannot access them by name.
you cannot write object.field
You need to have accessors to get their value
your code will be object.getFiled()
I'm unable to retrieve the data which is nested inside "Leagues" and "Season".
In the database below, I cannot retrieve Season 2016/2017 points and results.
I am able to access the data that is not nested, such as Email and Username without problems
"Users" :
"User1" : {
"Email" : "dfs#sdf.com",
"Last_login" : "5:15pm",
"Username" : "Test",
"Leagues" : {
"FootballLeague" : true,
"CricketLeague" : true
},
"Season" : {
"2017" : {
"Points" : 5,
"Results" : 2
"newdata" : {
"randomdata1: data1",
"randomdata2: data2"
},
}
"2018" : {
"Points" : 7,
"Results" : 2
}
}
The following class is what I'm using to store data as objects:
public class Users {
private String Username;
private String Email;
private String Last_login;
private Map<String, Boolean> Leagues;
private Map<String, thisSeason> Season;
public Users() {
}
//All getters and setters for the strings.
public Map<String, Boolean> get_joined_Leagues() {
return Leagues;
}
public void set_joined_Leagues(Map<String, Boolean> leagues) {
Leagues = leagues;
}
public Map<String, thisSeason> getSeason() {
return Season;
}
public void set_thisSeason(Map<String, thisSeason> season) {
Season = season;
}
public static class thisSeason {
private int Points;
private int Results;
private Map <String, thisNewData> newdata;
public thisSeason() {
}
public int getthisSeason_results() {
return Results;
}
public void setthisSeason_results(int resultsin) {
Results = resultsin;
}
public int getthisSeason_points() {
return Points;
}
public void setSeason_points(int Pointsin) {
Points = Pointsin;
}
public Map<String, thisNewData> getNewData() {
return newdata;
}
public void set_thisNewData(Map<String, thisNewData> newdata_in) {
newdata= newdata_in;
}
public static class thisNewData {
private String randomdata1;
private String randomdata2;
//Getters and Setters
}
Here is part of my Java class where I access the Database:
List<Users> usersList= new ArrayList<Users>();
DatabaseReference fbDB = FirebaseDatabase.getInstance().getReference();
fbDB.child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Users C = ds.getValue(Users.class);
usersList.add(C);
System.out.println(C.getSeason().getthisSeason_points()); //ERROR occurs here - null object reference
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I get a null object reference error as shown in the code above.
Also, on a slight side note - I'm aware my implementation for getting Leagues is incorrect. How can I retrieve the keys instead?
The main problems that I found in your code:
First, your Leagues object:
Well, it should not be a custom object at all, if it stays in the current structure, but a Map. This is the map object - a collection which has a key, and a value, just like a child in the Realtime Database.
If a league name (=key) didn't have a true (=value) next to it - the names could have been stored in String variables, but this is not the case, because every child in the Realtime Database must have a value, and storing a "dummy" value next to a league name makes each league a part of a Map. This current "dummy" is a boolean, and that's why this will be the leagues' data type:Map<String, Boolean> leagues.
Second, your Season object:
You are confusing between one season and many seasons. Your child - "Season" actually stores a lot of seasons. Thats why this case will be similar to the one above - each season's time is the key and the season itself is the value.
Therefore, the User class's variables should be:
private String Username;
private String Email;
private String Last_login;
private Map<String,Boolean> Leagues;
private Map<String, Season> Seasons;
I like convert below code to java stream,
HashMap<String, List<Data>> heMap = new HashMap<String, List<Data>>();
for (Data heData : obj) {
String id = heData.getData().getId() + heData.getPlanData().getCode()
+ heData.getPlanData().getId();
if (!heMap.containsKey(id)) {
CitizenHElist = new ArrayList<Data>();
CitizenHElist.add(heData);
heMap.put(id, CitizenHElist);
} else {
heMap.get(id).add(heData);
}
}
I tried the below code using stream, but i am not succeed on this.
heMap=obj.stream().collect(Collectors.toMap(t->getKey(t), obj.stream().collect(Collectors.toList())));
private String getKey(Data heData){
String id = heData.getData().getId() + heData.getPlanData().getCode()
+ heData.getPlanData().getId();
return id;
}
This is the job for groupingBy collector:
import static java.util.stream.Collectors.groupingBy;
Map<String, List<Data>> heMap = obj.stream().collect(groupingBy(d -> getKey(d)));
Note that this will use some unspecified implementations of Map and List. Currently, it happens to be HashMap and ArrayList, but that might change in the future.
Grouping on the bases of a field -
import java.util.*;
import java.util.stream.*;
public class Main
{
public static void main (String[]args)
{
System.out.println ("Hello World");
List < Data > dataList = getDataList();
System.out.println (dataList);
Map < String, List < Data >> dataMap =
dataList.stream ().collect (Collectors.groupingBy (d->d.code));
System.out.println (dataMap);
}
static List < Data > getDataList(){
List < Data > dataList = new ArrayList <> ();
dataList.add (new Data (1, "Prince", "102"));
dataList.add (new Data (2, "Rahul", "102"));
dataList.add (new Data (3, "Sunny", "103"));
dataList.add (new Data (4, "Mitul", "104"));
dataList.add (new Data (5, "Amit", "105"));
dataList.add (new Data (6, "Ashish", "105"));
return dataList;
}
}
class Data
{
int id;
String name;
String code;
public Data (int id, String name, String code)
{
this.id = id;
this.name = name;
this.code = code;
}
public String toString ()
{
return String.format ("id:%s,name:%s,code:%s", id, name, code);
}
}
not sure your data structure but you want to do something like below, which is working.
import java.util.*;
import java.util.stream.Collectors;
class Data {
String stud_id;
String stud_name;
String stud_location;
public Data(String string, String string2, String string3) {
this.stud_id=string;
this.stud_location=string2;
this.stud_name=string3;
}
public Object getData() {
return this.stud_id;
}
}
class Temp3
{
public static void main(String args[])
{
Map<String, List<Data>> heMap=new HashMap<String, List<Data>>();
Data data1=new Data("1","11","111");
Data data2=new Data("2","22","222");
List<Data> obj=new ArrayList<Data>();
obj.add(data1);
obj.add(data2);
for (Data heData : obj)
{
String id = "2";
if (!heMap.containsKey(id))
{
ArrayList<Data> CitizenHElist = new ArrayList<Data>();
CitizenHElist.add(heData);
heMap.put(id, CitizenHElist);
}
else
{
heMap.get(id).add(heData);
}
}
heMap=obj.stream().collect(Collectors.groupingBy(w -> w.stud_location));
System.out.println(heMap);
}
}