Group HashMap items according to a specific key - java

I have a ArrayList>> which holds certain key-value entries. Like:-
ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String,String>>();
HashMap<String,String> map = new HashMap<String,String>();
map.put("NewId", newId);
map.put("Title", title);
map.put("Description", description);
myList.add(map);
"NewId" can be similar for multiple entries.
Also I have an Array of colors:-
String[] colors = new String[]{"#1F1A17", "#62934D", "#F9B03F", "#7959BC", "#74B8DE", "#E65641", "#7CC8BB", "#D7CE5D", "#D6BE95", "#B694D1"};
I want to now group all the entries with same "NewId" together and assign them the first color, other entries with next similar "NewId" with the second color and so on till items with first 10 same "NewId" get assigned with their respective colors.
eg:- before grouping
NewId Title Description
101 title1 des1
102 title2 des2
103 title3 des3
101 title4 des4
102 title5 des5
103 title6 des6
after grouping
NewId Title Description
101 title1 des1 ------> color1
101 title4 des4 ------> color1
102 title2 des2 ------> color2
102 title5 des5 ------> color2
103 title3 des3 ------> color3
103 title6 des6 ------> color3
How can I achieve this?

You're going to need a pretty impressive loop. Advanced for loops are really going to help. If I understand you right, you want something like this
int i = 0; //Or whatever the starting id number is
int j = 0; //For managing the color assigning
//If you want a new hash map Map<String, String> colorsMap = new HashMap<>();
for (HashMap<String, String> loopMap : myList) {
while (i < colors.length) {
if (loopMap.containsKey("" + i) {
loopMap.put("" + i + "color", colors[j]);
//Or if you want to make a new HashMap: colorsMap.put("" + i, colors[j]);
}
i++; //Now start with next id entry
j++; //And next color
}
i = 0; //Or starting id num
j = 0; //Starting color index
}
//If you are making a new hash map: myList.add(colorsMap);
I would personally use a class to put the data, title, description, and color data together, it will make things a lot simpler. And it would let you add methods to better

you can add a custom list class:
public class MyList {
private ArrayList<HashMap<String, String>> list = new ArrayList<>();
public boolean add(HashMap<String, String> map) {
return list.add(map);
}
public void setColor(String newId, String color) {
for (HashMap<String, String> m : list)
if (m.containsKey(newId))
m.put("color", color);
}
public String getGroupKey(String key, int i) {
ArrayList<String> uniqeList = getUniqKeyList(key);
Collections.sort(uniqeList);
return uniqeList.get(i);
}
public ArrayList<String> getUniqKeyList(String key){
ArrayList<String> l = new ArrayList<>();
for (HashMap<String, String> m : list)
if(!l.contains(m.get(key)))
l.add(m.get(key));
return l;
}
}
and in main every thing is clear and simple :
public static void main(String[] args) throws Exception {
MyList myList = new MyList();
HashMap<String,String> map = new HashMap<String,String>();
map.put("NewId", newId);
map.put("Title", title);
map.put("Description", description);
myList.add(map);
String[] colors = new String[]{"#1F1A17", "#62934D","#B694D1"};
int i=0;
while (true) {
if(i == colors.length)
break;
String s = myList.getGroupKey("NewId", i);
if(s == null)
break;
else
myList.setColor(s, colors[i++]);
}
}

I would suggest, instead of using an Arraylist<HashMap<string, string>> you use a HashMap<string, List<MyCustomObject>>. The CustomObject class will hold attributes NewId, Title and Description. The Key for this hashmap is the NewId attribute. This is important because you are assigning colors per value for NewId. Using this approach, you can assign one color per entry in your map.

Related

Pick objects that contain all or one but not more?

So I have an object(Drink) with a Map of ingredients and I want to go through a List of them.
I would like to find any Drink that as only the ingredients I search for, and not ones that have any other ingredients.
drinkA.ingredients("water","sugar","salt")
drinkB.ingredients("sugar","salt")
drinkC.ingredients("water")
drinkD.ingredients("sugar")
drinkE.ingredients("salt")
drinkF.ingredients("water","sugar")
drinkG.ingredients("water","salt")
So if I search for water and salt I want to see
drinkC
drinkE
drinkG
This is what I have but it only gives me Drinks with the ingredients I've searched for and more.
public void findSearchResults(String searchRegex, Gui gui) {
if(searchRegex.equals("") || searchRegex == null){
return;
}
List<String> multiSearch = new ArrayList<String>();
if(searchRegex.contains(",")){
multiSearch = Arrays.asList(searchRegex.split(","));
}else{
multiSearch.add(searchRegex);
}
int originSize = multiSearch.size();
gui.drinksToDisplay = new ArrayList<Drink>();
for(Drink d : allDrinks){
int regexIn = 0;
List<String> tempStrs = new ArrayList<String>();
tempStrs.addAll(multiSearch);
if(gui.searchStyle.equals("Has only Ingredients")){
Map<String, String> ingreds = d.getIngredients();
Set<Entry<String, String>> ingredsSet = ingreds.entrySet();
Iterator<Entry<String, String>> ingredsIter = ingredsSet.iterator();
while(ingredsIter.hasNext()){
Entry<String, String> e = ingredsIter.next();
for(String s : tempStrs){
if(e.getKey().toLowerCase().contains(s.toLowerCase())){
tempStrs.remove(s);
regexIn++;
break;
}
}
if(regexIn == originSize && tempStrs.isEmpty()){
gui.drinksToDisplay.add(d);
break;
}
}
}
}
}
edit: I added some more code and a little more information on what I want to acomplish

Adding element to array of array

I have an array of arrays with color variable
Color [] [] bin = new Color [64] [];
afterwards I want to insert colors into this array
Im looping through a list of colors and tmpColor is the particular color in the loop. I need to insert it into the specific loop it belongs.
int idx = 16* (tmpColor.getRed()/64) + 4*(tmpColor.getGreen()/64) + (tmpColor.getBlue()/64);
bin[idx].push(tmpColor);
However this doesn't seem to work. How do I add a color into the array in the specific index?
How I solve it is the following: instead of creating an array of arrays I created and array of ArrayLists
int size = 64;
ArrayList<Color>[] lists = new ArrayList[size];
for( int i = 0; i < size; i++) {
lists[i] = new ArrayList<Color>();
}
After that I pushed the elements to their particular bin ( in this case in lists)
lists[idx].add(tmpColor);
Afterwards getting the lenght and the first color in the array is s follows:
for (ArrayList<Color> p : lists){
System.out.println("size of bin" + p.size());
if (p.isEmpty())
continue;
else {
System.out.println("list" + p.get(0));
}
}
If you need a List of colors for your index you can use a Map:
private Map<Integer, List<Color>> bin = new HashMap<Integer, List<Color>>();
int idx = 16* (tmpColor.getRed()/64) + 4*(tmpColor.getGreen()/64) + (tmpColor.getBlue()/64);
if(bin.get(idx)==null) bin.put(idx, new ArrayList<Color>());
bin.get(idx).add(tmpColor); //This should be exactly what you need
You can use also different structures like List<List<Color>> or List<Color>[]. Every structure relays on a List since List can be updated and created without knowing the initial length.
What I would do is create a separate class for color bin and some useful methods within:
public class Bin{
private List<Color> colors = new ArrayList<Color>();
public void addColor(Color col){
this.colors.add(col);
}
public List<Color> getColors(){
return this.colors;
}
public boolean hasColor(Color col){
return colors.contains(col);
}
//and so on...
}
And the best structure for your goal now is a map with lazy initialization:
private Map<Integer, Bin> myBinsOfColors = new HashMap<Integer, Bin>();
int idx = 16* (tmpColor.getRed()/64) + 4*(tmpColor.getGreen()/64) + (tmpColor.getBlue()/64);
if(myBinsOfColors.get(idx)==null) myBinsOfColors.put(idx, new Bin()); //Lazy
myBinsOfColors.get(idx).addColor(tmpColor); //This should be exactly what you need
To get the avarage and the number of colors you can implement two methods in the Bin class:
public class Bin{
private List<Color> colors = new ArrayList<Color>();
//As above.
public Color calculateAverage() {
Integer red = 0;
Integer blue = 0;
Integer green = 0;
if(!colors.isEmpty()) {
for (Color col : colors) {
red+= col.getRed();
green+= col.getGreen();
blue+= col.getBlue();
}
return new Color(red/colors.size(), green/colors.size(), blue/colors.size());
}
return null;
}
public int getColorCount(){
return this.colors.size();
}
//and so on...
}

Jfreechart: how to get the individual items in a BoxAndWhiskerChart

I am generating a box and whisker chart with one item per category.I also want to generate a report with the mean, median and all the values per item in the BoxPlot. So, after i create the dataset, defaultboxandwhiskercategorydataset based on the categoryType, I call the method convertReportData to fetch each item in the defaultboxandwhiskercategorydataset and save the mean, median etc into another data object later for report generation. But it just prints only one category. Could anyone please help me to figure out what is wrong?
My boxplot
Code:
public static BoxAndWhiskerCategoryDataset createDataset() {
startTime = inputData.getItimeFrom();
endTime = inputData.getItimeTo();
List<String> categorylist = new ArrayList<>();
categorylist.add("Distance 0-20");
categorylist.add("Distance 20-40");
categorylist.add("Distance 40-60");
categorylist.add("Distance 60-80");
categorylist.add("Distance 80-100");
categorylist.add("Distance >100");
Map<String, List<Double>> map = new HashMap<String, List<Double>>();
map = addDistance(values_list);
DefaultBoxAndWhiskerCategoryDataset defaultboxandwhiskercategorydataset = new DefaultBoxAndWhiskerCategoryDataset();
for (String categoryType : categorylist) {
map.remove(null);
for (Map.Entry<String, List<Double>> entry : map.entrySet()) {
if (entry.getKey().equalsIgnoreCase(categoryType)) {
defaultboxandwhiskercategorydataset.add(entry.getValue(),
categoryType, " ");
}
}
}
convertReportData(defaultboxandwhiskercategorydataset, categorylist);
return defaultboxandwhiskercategorydataset;
}
private static void convertReportData(DefaultBoxAndWhiskerCategoryDataset boxandwhiskercategorydataset, List<String> latencyTypelist) {
report = new HashMap<>();
for (int i = 0; i < boxandwhiskercategorydataset.getColumnKeys().size(); i++) {
BoxAndWhiskerItem item = boxandwhiskercategorydataset.getItem(i, 0);
ReportData data = new ReportData();
data.setMean(item.getMean());
data.setMedian(item.getMedian());
data.setQ1(item.getQ1());
data.setQ3(item.getQ3());
data.setMaxOutlier(item.getMaxOutlier());
data.setMaxRegularNumber(item.getMaxRegularValue());
data.setMinOutlier(item.getMinOutlier());
data.setMinRegularNumber(item.getMinRegularValue());
data.setOutliers(item.getOutliers());
report.put(boxandwhiskercategorydataset.getRowKey(i).toString(),
data);
}
}
The problem is with
for (int i = 0; i < boxandwhiskercategorydataset.getColumnKeys().size(); i++) {
you are using getColumnKeys whereas you have only one Column. It should have been,
for (int i = 0; i < boxandwhiskercategorydataset.getRowKeys().size(); i++) {

How to add different child lists for different parents lists in ExpandableListView for Android?

I'm using an ExpandableListView to get an expandable list. I have 3 expandable "parent" lists: Price, Details, Notes. I want to be able to add unique child lists for each parent list. But the way its set up now, the same child list is being added for each parent list. How do I make it so I can add unique, separate child lists for Price, Details, and Notes?
Here is my code:
public class Assignment extends ExpandableListActivity {
int listFlag = 0;
#SuppressWarnings("unchecked")
public void onCreate(Bundle savedInstanceState) {
try{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_assignment);
SimpleExpandableListAdapter expListAdapter =
new SimpleExpandableListAdapter(
this,
createGroupList(), // Creating group List.
R.layout.group_row, // Group item layout XML.
new String[] { "Group Item" }, // the key of group item.
new int[] { R.id.row_name }, // ID of each group item.-Data under the key goes into this TextView.
createChildList(), // childData describes second-level entries.
R.layout.child_row, // Layout for sub-level entries(second level).
new String[] {"Sub Item"}, // Keys in childData maps to display.
new int[] { R.id.grp_child} // Data under the keys above go into these TextViews.
);
setListAdapter( expListAdapter ); // setting the adapter in the list.
}catch(Exception e){
System.out.println("Errrr +++ " + e.getMessage());
}
}
//Create Headings of Assignment attributes
private List createGroupList() {
ArrayList result = new ArrayList();
//Create string array for Topic headings
String[] topics = {"Price", "Details", "Notes"};
//Iterate through array of names to lay them out correctly
for( int i = 0 ; i < 3 ; ++i ) {
listFlag = i;
HashMap m = new HashMap();
m.put( "Group Item", topics[i] ); // the key and it's value.
result.add( m );
}
return (List)result;
}
#SuppressWarnings("unchecked")
private List createChildList() {
ArrayList result = new ArrayList();
for( int i = 0 ; i < 3 ; ++i ) { // this -15 is the number of groups(Here it's fifteen)
/* each group need each HashMap-Here for each group we have 3 subgroups */
ArrayList secList = new ArrayList();
for( int n = 0 ; n < 1 ; n++ ) {
HashMap child = new HashMap();
child.put( "Sub Item", " "test"));
secList.add( child );
}
result.add( secList );
}
return result;
}
Android does not support nested listviews.
Your createChildList needs to return a List<ArrayList<HashMap<String, String>>>.
Your createChildList should look something like this:
private List<ArrayList<HashMap<String, String>>> createChildList(int maxValue) {
ArrayList<ArrayList<HashMap<String, String>>> groupList =
new ArrayList<ArrayList<HashMap<String, String>>>();
for (int i = 0; i <= maxValue; i++) {
ArrayList<HashMap<String, String>> childList =
new ArrayList<HashMap<String, String>>();
for (int j = 0; j <= maxValue; j++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("Sub Item", "test: " + String.valueOf(j));
childList.add(map);
}
groupList.add(childList);
}
return groupList;
}
Let me know if that works.

Java compare two map

In java, I want to compare two maps, like below, do we have existing API to do this ?
Thanks
Map<String, String> beforeMap ;
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap ;
afterMap.put("a", "1");
afterMap.put("c", "333");
//--- it should give me:
b is missing, c value changed from '3' to '333'
I'd use removeAll() functionality of Set to to do set differences of keys to find additions and deletions. Actual changes can be detected by doing a set difference using the entry set as HashMap.Entry implements equals() using both key and value.
Set<String> removedKeys = new HashSet<String>(beforeMap.keySet());
removedKeys.removeAll(afterMap.keySet());
Set<String> addedKeys = new HashSet<String>(afterMap.keySet());
addedKeys.removeAll(beforeMap.keySet());
Set<Entry<String, String>> changedEntries = new HashSet<Entry<String, String>>(
afterMap.entrySet());
changedEntries.removeAll(beforeMap.entrySet());
System.out.println("added " + addedKeys);
System.out.println("removed " + removedKeys);
System.out.println("changed " + changedEntries);
Output
added []
removed [b]
changed [c=333]
The Guava Maps class has some methods for calulating the differences between a pair of maps. However, these methods give you a data structure representing the differences not a pretty-printed string.
There isn't any out of the box component to help with that. You'll probably have to code it unfortunately. The good news is the logic is pretty easy.
Depending upon your particular needs, you might also consider using other applications designed to do this work, like diff. You could write the two maps to two different files, and diff the files.
String output = new String();
for (String key:beforeMap.getKeys()){
String beforeValue = beforeMap.getValue(key);
String afterValue = afterMap.getValue(key);
//nullsafe
if(beforeValue.equals(afterValue){}
else if (afterValue == null){
output = output + key + " is missing, ";
continue;
}else {
output = output + key + " has changed from " + beforeValue + " to " + afterValue + " , ";
}
afterMap.remove(key);
}
for (String key:afterMap.getKeys()){
output = output + key + " was added with value " + afterMap.getValue(key) + ", ";
}
if(output == null){
output = "Same map";
}
output = output.substring(0,output.length-2);
System.out.println(output);
You could use a custom object that contains the key and the value (actually Map does this internally, hidden from the user, so we can't use that)
Put these tuples into a Set
To compare two sets, convert them both to arrays, sort the arrays and walk both arrays from begin to end in parallel, stepping down the first array if it's key is smaller than the key in the second array, and vise versa.
class Tuple implements Comparable<Tuple>
{
public String key;
public String value;
public Tuple(String key, String value)
{
this.key = key;
this.value = value;
}
#Override
public int compareTo(Tuple o)
{
return key.compareTo(o.key);
}
}
public static void main(String[] args)
{
// TreeSet is already sorted. If you use HashSet, use Arrays.sort()
Set<Tuple> beforeSet = new TreeSet<>();
beforeSet.add(new Tuple("a", "1"));
beforeSet.add(new Tuple("b", "2"));
beforeSet.add(new Tuple("c", "4"));
Set<Tuple> afterSet = new TreeSet<>();
afterSet.add(new Tuple("a", "1"));
afterSet.add(new Tuple("c", "333"));
afterSet.add(new Tuple("aa", "4"));
Tuple[] beforeArray = beforeSet.toArray(new Tuple[beforeSet.size()]);
Tuple[] afterArray = afterSet.toArray(new Tuple[afterSet.size()]);
int beforePtr = 0;
int afterPtr = 0;
while (beforePtr < beforeArray.length || afterPtr < afterArray.length)
{
int difference = afterPtr >= afterArray.length? -1 : beforePtr >= beforeArray.length? 1 : beforeArray[beforePtr].compareTo(afterArray[afterPtr]);
if (difference == 0)
{
if (!beforeArray[beforePtr].value.equals(afterArray[afterPtr].value))
{
System.out.println(beforeArray[beforePtr].key + " value changed from '" + beforeArray[beforePtr].value + "' to '" + afterArray[afterPtr].value + "'");
}
beforePtr++;
afterPtr++;
}
else if (difference < 0)
{
System.out.println(beforeArray[beforePtr].key + " is missing");
beforePtr++;
}
else
{
System.out.println(afterArray[afterPtr].key + " is added");
afterPtr++;
}
}
}
#user595234 To Compare the two Maps you can add the keys of a map to list and with those 2 lists you can use the methods retainAll() and removeAll() and add them to another common keys list and different keys list. Using the keys of the common list and different list you can iterate through map, using equals you can compare the maps.
public class Demo
{
public static void main(String[] args)
{
Map<String, String> beforeMap = new HashMap<String, String>();
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap = new HashMap<String, String>();
afterMap.put("a", "1");
afterMap.put("c", "333");
System.out.println("Before "+beforeMap);
System.out.println("After "+afterMap);
List<String> beforeList = getAllKeys(beforeMap);
List<String> afterList = getAllKeys(afterMap);
List<String> commonList1 = beforeList;
List<String> commonList2 = afterList;
List<String> diffList1 = getAllKeys(beforeMap);
List<String> diffList2 = getAllKeys(afterMap);
commonList1.retainAll(afterList);
commonList2.retainAll(beforeList);
diffList1.removeAll(commonList1);
diffList2.removeAll(commonList2);
System.out.println("Common List of before map "+commonList1);
System.out.println("Common List of after map "+commonList2);
System.out.println("Diff List of before map "+diffList1);
System.out.println("Diff List of after map "+diffList2);
if(commonList1!=null & commonList2!=null) // athough both the size are same
{
for (int i = 0; i < commonList1.size(); i++)
{
if ((beforeMap.get(commonList1.get(i))).equals(afterMap.get(commonList1.get(i))))
{
System.out.println("Equal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
else
{
System.out.println("Unequal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
}
}
if (CollectionUtils.isNotEmpty(diffList1))
{
for (int i = 0; i < diffList1.size(); i++)
{
System.out.println("Values present only in before map: "+beforeMap.get(diffList1.get(i)));
}
}
if (CollectionUtils.isNotEmpty(diffList2))
{
for (int i = 0; i < diffList2.size(); i++)
{
System.out.println("Values present only in after map: "+afterMap.get(diffList2.get(i)));
}
}
}
/** getAllKeys API adds the keys of the map to a list */
private static List<String> getAllKeys(Map<String, String> map1)
{
List<String> key = new ArrayList<String>();
if (map1 != null)
{
Iterator<String> mapIterator = map1.keySet().iterator();
while (mapIterator.hasNext())
{
key.add(mapIterator.next());
}
}
return key;
}
}
The below code will give you this output:
Before: {b=2, c=3, a=1}
After: {c=333, a=1}
Unequal: Before- 3 After- 333
Equal: Before- 1 After- 1
Values present only in before map: 2

Categories

Resources