i having an object with below information
TransHdr: id, order_num
TransItem: hdr_id, product_code, refnum, qty (child record)
transHdr.id=transItem.hdr_id
if let say 3 record can be found in TransItem,
parkA,112,10
parkA,112,6
parkB,113,10
i would like group it base on refnum, means that my result will be
parkA,112,16
parkB,113,10
i need a method that will loop the object (item level) and need to return transHdr object to other function. anyway to do this?
for (java.util.Iterator<ITransItem> groupTransItems = TransHdr.getTransItems().iterator();
groupTransItems.hasNext();) {
ITransItem _TransItem = groupTransItems.next();
if (null!=_TransItem.getRefNum()){
<question here..how do i group and sum up my item and become only 1 record?>
}
}
return newGroupingTransHdr;
}
Create a new Map with refnum as key and qty as value.
Map<String,Integer> qtyMap=new HashMap<String,Integer>();
while iterating, try
String refNum=transItem.getRefNum();
// Mark for removal ? if this is not the first item in the list with the refnum
boolean remove=true;
Integer currentQty=qtyMap.get(refNum);
if(currentQty==null){
currentQty=0;
// this doesnt exist already in the map, this is the first item with this reference
// number in the list, so you should keep this without removing
remove=false;
}
currentQty=currentQty+transItem.getQty();
qtyMap.put(refNum,currentQty);
// if the remove is true then remove this item from the list.
if(remove){
groupTransItems.remove();
}
This will sum up the qty for refnum's in the map and once your iteration is over, the map will have the sums of quantities for each refnum. You will have to iterate the list once more to set the current qty to each item from the map [EDIT] :- Added the iterating time removal.
Similar to the solution suggested in this post. You can have a Map with ref_num as key and TransItem as value.
TransHdr transHdr; // Externally given
Map<String, ITransItem> collapsedItems = new HashMap<String, ITransItem>();
List<ITransItem> items = transHdr.getItems();
transHdr.setItems(new ArrayList<ItransItem>());
for (ITransItem item : items) {
String ref_num = item.getRefNum();
ITransItem collapsedItem = collapsedItems.get(ref_num);
if (collapsedItem == null) {
collapsedItems.put(ref_num, item);
} else {
int qnt = item.getQnt();
collapsedItem.setQnt(collapsedItem.getQunt() + qnt);
}
}
transHdr.setItems(new ArrayList<ITransItem>(collapsedItems.values()));
Another way to accomplish what you want to do is to embed the logic in an add method on your TransHdr class.
pulic class TransHdr {
private String id;
private int orderNumber;
private Map<String, ITransItem> items;
public TransHdr(String id, int orderNumber) {
this.id = id;
this.orderNumber = orderNumber;
this.items = new HashMap<String, ITransItem>();
}
public void addItem(ITransItem item) {
String ref = item.getRefNum();
ITransItem currentItem = items.get(ref);
if (currentItem == null) {
items.put(ref, item);
} else {
int qnt = item.getQnt();
currentItem.setQnt(currentItem.getQnt() + qnt);
}
}
public Set<ITransItem> getItems() {
return items.values();
}
}
As you can see, there's multiple ways of doing this. The appropriate solution depends on what your requirements and use cases are.
Related
So I have this ArrayList of Product objects. What I'm doing is on click of + button, I am making an object of Product and setting all the attributes from ui; including 'quantity' and adding this object to ArrayList. Now, as I'm adding a single object on single click of + button, I'm getting duplicate Product objects with all same attributes other than, of course, 'quantity' count. If I add a product with quantity of 4, I get 4 objects of Product inside arraylist with different quantity 1,2,3 and 4. I only want to have Product object with maximum quantity inside the collection. I have used Comparator for this problem, but I am doing something wrong here. Please help find out what I'm doing wrong. Thanks. Here's the model of Product with getter and setters excluded from snippet.
Product:
private String category;
private String code;
private String description;
private String units;
private String weight;
private Integer tax;
private String pieces;
private Integer aliasFlag;
private Double price;
private Integer quantity;
private Integer taxAmount;
private Double totalAmount;
What I'm doing so far to compare two or more(as per the quantity count) objects of Product using Comparator is:
Collections.sort(mProductsToBeSent, new Comparator<Products>() {
#Override
public int compare(Products ob1, Products ob2) {
if (ob1.getCode().equals(ob2.getCode())) {
if (ob1.getQuantity()<ob2.getQuantity()){
mProductsToBeSent.remove(ob1);
}
}
return 0;
}
});
mProductToBeSent is my ArrayList that I'm gonna have to send as a Json, but since there is duplication, this won't do. I'm comparing 'Code' attribute of two subsequent objects for the same product and if it's true then I'm comparing the 'Quantity'. If it's true then I'm removing the lesser quantity object from the list. But I'm not getting desired output.
The output I'm getting right now:
[
Products{Aliasflag='0', Code ='BMA10K', Description=abc, Price=270.0, Quantity=1, Taxamount=0, Units='BAGS'},
Products{Aliasflag='0', Code ='BMA10K', Description=def, Price=270.0, Quantity=2, Taxamount=0, Units='BAGS'},
Products{Aliasflag='0', Code ='BMA10K', Description=ghi, Price=270.0, Quantity=3, Taxamount=0, Units='BAGS'},
Products{Aliasflag='0', Code ='BMA10K', Description=jkl, Price=270.0, Quantity=4, Taxamount=0, Units='BAGS'}]
As you can see, I'm trying to remove the first three objects to be deleted and only preserve the object with max quantity in the arraylist; that is 4th object--in this case.
Desired output :
[
Products{Aliasflag='0', Code ='BMA10K', Description=jkl, Price=270.0, Quantity=4, Taxamount=0, Units='BAGS'}]
The usual way to do this is not to add a different product into your list with just another quantity value, but to get the product out of the list and update its quantity.
Wrote as answer because I cannot just comment and I think it will help you.
You can do something like this :
mProductsToBeSent.stream()
.collect(Collectors.groupingBy(Product::getCode,
Collectors.maxBy(Comparator.comparing(Category::getQuantity))));
You will obtain a map Map<String, Optional<Product>>, now can convert it to a List in this way :
yourObtainedMap.entrySet()
.stream().map(entry -> entry.getValue().get())
.collect(Collectors.toList())
You can't remove elements from a list while you're sorting it.
I would do this as a comparator:
new Comparator<Products>() {
#Override
public int compare(Products ob1, Products ob2) {
if (ob1.getCode().equals(ob2.getCode())) {
if (ob1.getQuantity()<ob2.getQuantity()){
return -1;
} else if (ob1.getQuantity()<ob2.getQuantity()){
return 1;
} else {
return 0;
}
}
return 0;
}
}
You can then remove the duplicates:
String prevCode = "";
for (int i = mProductsToBeSent.size(); --i >= 0) {
Products prod = mProductsToBeSent.get(i);
if (prod.getCode().equals(prevCode)) {
mProductsToBeSent.remove(i);
} else {
prevCode = prod.getCode();
}
}
UPDATE:
But if you keep your list sorted by product code, you can remove duplicates whenever you're adding to the quantity:
private static final Comparator<Products> PRODUCTS_CODE_COMPARATOR = new Comparator<Products>() {
#Override
public int compare(Products ob1, Products ob2) {
return ob1.getCode().compareTo(ob2.getCode());
}
};
To add a Products object:
int pos = Collections.binarySearch(mProductsToBeSent, obj, PRODUCTS_CODE_COMPARATOR);
if (pos >= 0) {
// already in the list
Products obj2 = mProductsToBeSent.get(pos);
obj2.setQuantity(obj2.getQuantity() + obj.getQuantity());
} else {
// not found: insert obj
mProductsToBeSent.add(-pos-1, obj);
}
I have list of ObjectLocation, declared as
List<ObjectLocation> myLocations;
And here's how ObjectLocation looks like:
public class ObjectLocation {
int locationID, ratingCount = 0;
}
Ok now myLocations holds thousands of locationID. If I have a particular locationID, how do I search the contents of myLocations for the locationID, and get the searched locationID's index (within myLocations) and it's ratingCount?
Well, you loop through all of the elements in the list, and if the locationID match, you've found your element!
int idx=0;
for (ObjectLocation ol:myLocations){
if (ol.locationID==searchedLocationID){
// found at index idx!!
}
idx++;
}
More efficiently, you could have a Map<Integer,ObjectLocation> where the key is the locationID of the ObjectLocation, to get much faster lookups.
For this sort of lookup I'd switch to using a Map<Integer, ObjectLocation> and store entries in the map like this:
Map<Integer, List<ObjectLocation>> myLocationMap = new HashMap<>();
List<ObjectLocation> currentList = myLocationMap.get(oneLocation.locationID);
if(currentList == null) {
// We haven't stored anything at this locationID yet,
// so create a new List and add it to the Map under
// this locationID value.
currentList = new ArrayList<>();
myLocationMap.put(oneLocation.locationID, currentList);
}
currentList.add(oneLocation);
Now you can quickly get all of the ObjectLocation entries with a specific value for locationID by grabbing them from the map like this:
List<ObjectLocation> listOfLocations = myLocationMap.get(someLocationId);
This assumes that multiple ObjectLocation instances can have the same locationID value. If not then you wouldn't need a List<ObjectLocation> in the map, just a single ObjectLocation.
For you to easily search and find a your ObjectLocation objects, you should first define .equals(Object o) method, in ObjectLocation class, that allows one ObjectLocation to be compared to another. After that, all you have to do is use .indexOf(Object o)' to get the index of the ObjectLocation you are looking for. Then extract that object and use its information as exemplified in the code below:
public class ObjectLocation {
int locationID, ratingCount = 0;
public boolean equals(Object o)
{
if(!(o instanceof ObjectLocation))
return false;
ObjectLocation another = (ObjectLocation)o;
if( locationID == another.locationID && ratingCount == another.ratingCount)
return true;
else
return false;
}
public static void main(String[] args)
{
List<ObjectLocation> myLocations;
ObjectLocation findThisLocation;
ObjectLocation found;
//Additional code here
int index = myLocations.indexOf(findThisLocation);
found = myLocations.get(index);
int id = found.locationID;
int rating = found.ratingCount;
}
}
List<ObjectLocation> myLocations = new ArrayList<>();
int index =0;
int particularId = 1;//!your Id
int locationid = 0;
int ratingcount = 0;
for(int i =0; i < myLocations.size(); i++) {
if(myLocations.get(i).locationID == particularId) {
index = i;
locationid = myLocations.get(i).locationID;
ratingcount = myLocations.get(i).ratingCount;
}
}
For Java 8, I would use (without changing anything on the data structure like using a Map instead or knowing about ordering in the list):
Optional<ObjectLocation> found = myLocations.stream()
.filter(location -> location.locationID == particularLocationID)
.findAny();
if (found.isPresent() {
int ratingCount = found.get();
…
}
When you need more performance for single searches, you may try parallelStream() instead of stream().
How would I go about only inserting an item if the item does not have the same name as the other items in the arraylist within my insertUniqueItem() method?
public void insertUniqueItem()
{
}
public static void main(String[] args)
{
ShoppingCart sc = new ShoppingCart();
Item a = new Item("Kraft Cheese", 4, "\"Best Cheese in Town!\"");
Item b = new Item("Bottle of Water", 2.50, "\"Refreshing Water!\"");
sc.insertItem(a);
sc.insertItem(b);
sc.printInvoice();
sc.insertUniqueItem();
sc.print();
DecimalFormat df = new DecimalFormat("#.00");
System.out.println("Total Price: $" + df.format(sc.getTotal()));
}
}
I would probably use a LinkedHashMap<String, Item> instead, where the key is the name of the item. That way:
You still get to preserve ordering
You can easily and efficiently check whether there's already an entry for a given item name.
You'd have something like:
if (!map.containsKey(item.getName()) {
map.put(item.getName(), item);
}
This only works if you want all items to be unique in terms of name though. If you sometimes want to allow a duplicate name and sometimes not, you probably do want a list, and then you could have something like:
boolean containsItemName(ArrayList<Item> items, String name) {
for (Item item : items) {
if (item.getName().equals(name)) {
return true;
}
}
return false;
}
If you're using Java 8, you could use a stream-based solution:
boolean containsItemName(ArrayList<Item> items, String name) {
return items.stream().anyMatch(item -> item.getName().equals(name));
}
You need to check if an item with the same name already exists in your list:
public void insertUniqueItem(Item item) {
if(!contains(item)) {
cart.add(item);
}
}
private boolean contains(Item item) {
for(Item i : cart) {
if(i.getName().equals(item.getName())) {
return true;
}
}
return false;
}
You can modify your Item class to have the equals and hashcode methods as follows:
public class Item{
private String name;
public boolean equals(Object o){
if (o instanceOf Item and ((Item)o).getName().compareTo(name) == 0){
return true;
}
return false;
}
public int hashCode(){
return name.hashCode();
}
}
You can now use the contains method of the arrayList to determine if another item exists with the same name in the arrayList or not.
I recommend you to use a Set in your ShoppingCart instead of a List. Set will manage the unicity of your items. Make sure to have equals method override in your Item class
Why you do not using Set ?
Adds the specified element to this set if it is not already present
(optional operation). More formally, adds the specified element e to
this set if the set contains no element e2 such that (e==null ?
e2==null : e.equals(e2)). If this set already contains the element,
the call leaves the set unchanged and returns false. In combination
with the restriction on constructors, this ensures that sets never
contain duplicate elements.
too simple :
override equal and hashCode on Item class :
class Item {
private String title ;
private String description ;
// getter & setter
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false
Item item = (Item) o;
return Objects.equals(title,item.title) ; // Or any statement you want
}
#Override
public int hashCode() {
return Objects.hash(title); //same statement like equals method
}
}
Now :
List<Item> listCollection = new ArrayList<>();
Item a = new Item("A", "Best Cheese in Town!");
Item b = new Item("B", "Refreshing Water!");
// add items ...
listCollection.add(a);
listCollection.add(b);
Set<Item> setCollection = new HashSet<>(listCollection);
Item duplicate = new Item("B","New Description");
setCollection.add(duplicate); // Not added to setCollection
Sorry if the title isn't clear, I wasn't sure how to word it. I have an arraylist of objects and within each of these objects I store an integer value referring to a category and one referring to an ID.
I want to find the number of unique combinations of category and IDs that there are.
So at the moment I have
for(Object object: listofObjects){
//For each unique type of object.getID
//For each unique type of object.getCategory
//Add 1 to counter
}
I can't figure out how to do this. Doing things like for(int cat: object.getCategory()) brings up an error.
I can add the values to a new list within the initial for each loop like so,
ArrayList<Integer> aList= new ArrayList<Integer>();
for (Object object : spriteExplore) {
aList.add(object.getCategory());
}
for (int cat : aList) {
testCounter++;
}
but this obviosuly does not take into account uniqueness and also makes it awkward for factoring in the other variable of ID.
I feel like there is probably some easier work around that I am missing. Any advice?
Thanks in advance.
So you list of UserDefine object in ArrayList and you want to find unique Object.Just create set from list.
For e.g Suppose you have
List<Customer> list=new ArrayList<Custeomer>();
list.add(new Customer("A",12));
list.add(new Customer("B",13));
list.add(new Customer("A",12));
now
create set From this list
Set<Customer> set = new HashSet<Customer>(list);
this will have unique Customer
IMP : dont forget to override equals and hashcode method for Customer
Your best approach would be storing the data correctly.
It's possible that you still need to store non-unique items, if that's so - continue using an ArrayList, but in addition, use the following:
Override the hashcode & equels function as shown in this link:
What issues should be considered when overriding equals and hashCode in Java?
Then, use a Set (HashSet would probably be enough for you) to store all your objects. This data structure will disregard elements which are not unique to elements already inside the set.
Then, all you need to do is query the size of the set, and that gives you the amount of unique elements in the list.
I don't know any library that does this automatically, but you can do it manually using sets. Sets will retain only unique object so if you try to add the same value twice it will only keep one reference.
Set<Integer> categories = new HashSet<Integer>();
Set<Integer> ids= new HashSet<Integer>();
for (Object object : listofObjects) {
categories.add(object.getCategory());
ids.add(object.getID());
}
Then you get the number of unique categories / ids by doing
categories.size()
ids.size()
And all your unique values are stored in the sets if you want to use them.
I would look into using a (Hash)Map<Integer, Integer>. Then just have 1 foreach loop, checking to see if the value of Map<object.getId(), object.getCategory()> is null by checking if map.get(object.getId()) is null - if it is, then this pair does not exist yet, so add this pair into the map by using map.put(object.getId(), object.getCategory()). If not, do nothing. Then at the end, to find the number of unique pairs you can just use map.size()
Hope this helps
Map<Integer,List<Integer>> uniqueCombinations = new HashMap<Integer,List<Integer>>();
for (Object object : listofObjects) {
if(uniqueCombinations.get(object.getCategoryId())==null) {
uniqueCombinations.put(object.getCategoryId(), new LinkedList<Integer>);
}
uniqueCombinations.get(object.getCategoryId()).add(object.getId());
}
return uniqueCombinations.size()
I believe you want unique combinations of both category and id, right?
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class SO {
class MyObject{
private int id;
private int category;
private String name;
private MyObject(int id, int category,String name) {
super();
this.id = id;
this.category = category;
this.name = name;
}
protected int getId() {
return id;
}
protected int getCategory() {
return category;
}
#Override
public String toString() {
return "MyObject [id=" + id + ", category=" + category + ", name=" + name + "]";
}
}
public static void main(String[] args) {
SO so = new SO();
List<Object> listofObjects = new ArrayList<Object>();
listofObjects.add(so.new MyObject(1,1,"One"));
listofObjects.add(so.new MyObject(1,1,"Two"));
listofObjects.add(so.new MyObject(1,2,"Three"));
Map<String,List<MyObject>> combinations = new HashMap<String,List<MyObject>>();
for(Object object: listofObjects ){
//For each unique type of object.getID
//For each unique type of object.getCategory
//Add 1 to counter
if (object instanceof MyObject){
MyObject obj = (MyObject)object;
String unique = obj.id+"-"+obj.category;
if (combinations.get(unique) == null){
combinations.put(unique, new ArrayList<MyObject>());
}
combinations.get(unique).add(obj);
}
}
System.out.println(combinations);
//counts
for(Entry<String,List<MyObject>> entry:combinations.entrySet()){
System.out.println(entry.getKey()+"="+entry.getValue().size());
}
}
}
Use the Hashmap to save occurence. Dont forget to implement hashcode und equals Methods. You can generate them if you work with Eclipse IDE.
public static void main(String[] args) {
List<MyObject> myObjects = Arrays.asList(new MyObject(1, 2), new MyObject(2, 3), new MyObject(3, 4), new MyObject(3, 4));
Map<MyObject, Integer> map = new HashMap<>();
for (MyObject myObject : myObjects) {
Integer counter = map.get(myObject);
if(counter == null){
counter = 1;
} else {
counter = counter + 1;
}
map.put(myObject, counter);
}
long uniqueness = 0;
for(Integer i : map.values()){
if(i == 1){
++uniqueness;
}
}
System.out.println(uniqueness);
}
The last part can be replaced by this one line expression if you are working with Java 8:
long uniqueness = map.values().stream().filter(i -> i == 1).count();
I have an Arraylist of Records.
package com.demo.myproject;
public class Records
{
String countryName;
long numberOfDays;
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public long getNumberOfDays() {
return numberOfDays;
}
public void setNumberOfDays(long numberOfDays) {
this.numberOfDays = numberOfDays;
}
Records(long days,String cName)
{
numberOfDays=days;
countryName=cName;
}
}
My Arraylist<Records> is containing the values
Singapore 12
Canada 3
United Sates 12
Singapore 21
I need to modify it such that my output is
Canada 3
Singapore 33
United States 12
Please help me with solution,approach.
You could store your Records in a Map, where the key would be the country.
When you receive a new Record, check if the country already is in the map, if it is, add the number of days, if not create it.
Map<String, Record> map = new HashMap<String, Record> ();
addRecord(map, someRecord);
private void addRecord(Map<String, Record> map, Record record) {
Record inMap = map.get(record.getCountryName());
if (inMap == null) {
inMap = record;
} else {
inMap.setNumberOfDays(inMap.getNumberOfDays() + record.getNumberOfDays());
}
map.put(record.getCountryName(), inMap);
}
Notes:
I have assumed that it is fine to modify the records - if not just create a new one using the sum of the days.
you can still get the collection of records by calling map.values(); and iterate over them
ArrayList is not very well suited for your use case. If you really need to stick to ArrayList, for evey new record, you would need to loop over the list, check if one of the records in the list has the same country as the new record, update that record if you find it, or add a new record if not.
public class RecordsMain {
static ArrayList<Records> al = new ArrayList<Records>();
static boolean flag = false;
public static void main(String[] args) {
Records rec1 = new Records(12,"Singapore");
Records rec2 = new Records(3,"Canada");
Records rec3 = new Records(12,"United States");
Records rec4 = new Records(21,"Singapore");
addToList(rec1);
addToList(rec2);
addToList(rec3);
addToList(rec4);
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i).getCountryName() + " :: " + al.get(i).getNumberOfDays());
}
}
public static void addToList(Records records) {
for (int i = 0; i < al.size(); i++) {
if(al.get(i).getCountryName().equals(records.getCountryName())) {
al.get(i).setNumberOfDays(al.get(i).getNumberOfDays()+records.getNumberOfDays());
flag=true;
}
}
if (flag == false)
al.add(records);
}
}
Note:
The function addToList adds records and while adding itself checks whether the CountryNames are duplicate, if they are it adds the No of days and does not marks any new entry to the ArrayList.
I was not sure if you were looking for sorting of the List too, thus did not try that.
I suppose you create these records on your own. If you don't need any specific order of the elements you should use the HashMap and as assylias said - create country elements only when they doesn't exist. When you need to keep the order of elements (or sort them later by name etc) you can still use the ArrayList and "indexOf()" method to easily find them.
I dont know what exactly you want to do there but if you want to sort it with specific criteria then You could use comparable or comparator interfaces to sort your records using your criteria in ArrayList And use collections.sort() method to sort it.