I have set up a test that:
retrieves data concerning several court cases: each court case is stored in a CourtCase object
a set of CourtCase objects is then stored in a Map
I retrieve these data twice (from two different sources) so I end up with two Maps
The data within the objects should be the same between the Maps, but the order of the objects within the Maps may not be:
Map1:
A, case1 - B, case2 - C, case3
Map2:
B, case2 - A, case1 - C, case3
How can I best compare these two Maps?
Map#equals does not care about the order. As long as your 2 maps contain the same mapping it will return true.
Map#equals uses Set#equals method, applied to the entry set. Set#equals contract:
Returns true if the specified object is also a set, the two sets have the same size, and every member of the specified set is contained in this set (or equivalently, every member of this set is contained in the specified set).
Note: this assumes that your CourtCase objects have proper equals and hashcode methods to be compared.
Map implementations provides an equals method which do the trick. Map.equals
#user973718 the best to compare two map objects in java is - 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.
The below code gives 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
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
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);
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;
}
}
Related
I have a list of itemMap (Map<ArrayList<String>, Integer> itemMap = new HashMap<ArrayList<String>, Integer>() )
containing the following elments
{ [File3, File2]=4,
[File2, File3]=2,
[File1, File2]=6,
[File1, File3]=2,
[File3, File1]=6,
[File2, File1]=6 }
I want to obtain a list containing no duplicates. (in my case a duplicate is a list containing same elements of another list).Example (F1,F2) and (F2,F1) are the same in my work.
So I want to obtain the following result:
{ [File3, File2]=6,
[File1, File3]=8,
[File1, File2]=12 }
As you see I sum the counts of duplicates but I keep one of the duplicates in my hashmap.
Can anybody help me with a simple code and thank you.
My own try was a fail:
HashMap<List<String>,Integer> myobjectListB = new HashMap<List<String>,Integer>();
for (List <String> key : itemMap.keySet()){
for (List <String> y : itemMap.keySet()){
if((key.containsAll(y) && (!key.equals(y))) && (key.size())==y.size()) {
int count = itemMap.get(key)+itemMap.get(y);
myobjectListB.put(key, count);
}
}
}
System.out.println("object list"+ myobjectListB);
}
If you replace ArrayList with a HashSet it will work the way you intend it to. That's because the Map interface only stores one value per key, and it determines if two keys are equal using the equals method. Two ArrayLists containing the same objects in different order will return false when compared, but two HashSets containing the same objects in different order will return true
I have wrote a method where you get a new map without duplicates. When you add values to the new map, it always check if the list contains in the keyset and also check the swapped list is also contains in the keyset. So there won't be any duplicates.
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<ArrayList<String>, Integer> itemMap = new HashMap<ArrayList<String>, Integer>();
itemMap.put(new ArrayList<>(Arrays.asList("File3", "File2")), 4);
itemMap.put(new ArrayList<>(Arrays.asList("File2", "File3")), 2);
itemMap.put(new ArrayList<>(Arrays.asList("File1", "File2")), 6);
itemMap.put(new ArrayList<>(Arrays.asList("File1", "File3")), 2);
itemMap.put(new ArrayList<>(Arrays.asList("File3", "File1")), 6);
itemMap.put(new ArrayList<>(Arrays.asList("File2", "File1")), 6);
System.out.println(removeDuplicates(itemMap));
}
static Map<ArrayList<String>, Integer> removeDuplicates(Map<ArrayList<String>, Integer> map) {
Map<ArrayList<String>, Integer> convertedMap = new HashMap<ArrayList<String>, Integer>();
for (ArrayList<String> list : map.keySet()) {
if (!convertedMap.keySet().contains(list)) {
Collections.swap(list, 0, 1);
if (!convertedMap.keySet().contains(list)) {
convertedMap.put(list, map.get(list));
}
}
}
return convertedMap;
}
}
I struggle with generating all possible combinations of values of a List of Attributes. As an example, for three attributes A, B,C, with the following values:{a1,a2} for A ,{b1,b2} for B, and {c1,c2} for C, I should get 8 combinations:
a1,b1,c1
a1,b1,c2
a1,b2,c1
a1,b2,c2
a2,b1,c1
a2,b1,c2
a2,b2,c1
a2,b2,c2
I used the following two recursive java functions where attribute_to_domain is a Map where we put each attribute as a key and its values as a value, and we add each combination as an <ArrayList<String> toenumerate_tuples as an ArrayList<ArrayList<String>>
public void fillTuples(Map<String, Set<String>> attribute_to_domain, ArrayList<String> attributes, ArrayList<ArrayList<String>> enumerate_tuples)
{
for (Map.Entry<String, Set<String>> entrySet :attribute_to_domain.entrySet()) {
String attribute=entrySet.getKey();
attributes.add(attribute);
}
int pos = 0;
Set<String> domain = attribute_to_domain.get(attributes.get(pos));
for (Iterator<String> it = domain.iterator(); it.hasNext();) {
String val = it.next();
ArrayList<String> tuple=new ArrayList<String>();
tuple.add(val);
fillTuples(attribute_to_domain, attributes, 1, tuple, enumerate_tuples);
tuple.remove(tuple.size()-1);
assert(tuple.isEmpty());
}
}
public void fillTuples(Map<String, Set<String>> attribute_to_domain, ArrayList<String> attributes, int pos, ArrayList<String> tuple, ArrayList<ArrayList<String>> enumerate_tuples)
{
assert(tuple.size() == pos);
if (pos == attributes.size())
{
enumerate_tuples.add(tuple);
return;
}
Set<String> domain = attribute_to_domain.get(attributes.get(pos));
for (Iterator<String> it = domain.iterator(); it.hasNext();) {
String val = it.next();
tuple.add(val);
fillTuples(attribute_to_domain, attributes, pos+1, tuple, enumerate_tuples);
tuple.remove(tuple.size()-1);
}
}
The problem that I get enumerate_tuples with empty elements and I can not keep changes that happened on it through the calls.
How can I solve this problem, please? Thanks in advance.
There is a simpler and faster solution, one that does not require recursion.
The number of output combinations can be calculated in advanced: multiplication of attributes in your case 2*2*2 but it is true for every combination.
Furthermore, we can calculate which value will be placed in each combination based on the combination index. if we assume combination index goes from 0 to 7:
for A:
- combinations 0-3 will contain a1
- combinations 4-7 will contain a2
for B
- combinations 0,1,4,5 will contain b1
- combinations 2,3,6,7 will contain b2
for C
- combinations 0,2,4,6 will contain c1
- combinations 1,3,5,7 will contain c2
so the formula for value placement is based on the combination index, the order of the attributes (A first etc) and the order of the values in the attribute.
the complexity of this algorithm is o(n*m) where n is number of attributes and m number of values.
Revised from Cartesian product of arbitrary sets in Java
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class CartesianProduct {
public static Set<Set<Object> > cartesianProduct(Set<?>... sets) {
if (sets.length < 2)
throw new IllegalArgumentException(
"Can't have a product of fewer than two sets (got " +
sets.length + ")");
return _cartesianProduct(0, sets);
}
private static Set<Set<Object> > _cartesianProduct(int index, Set<?>... sets) {
Set<Set<Object> > ret = new TreeSet<Set<Object> >(new Comparator<Set<Object> >() {
#Override
public int compare(Set<Object> o1, Set<Object> o2) {
return o1.toString().compareTo(o2.toString());
}
});
if (index == sets.length) {
ret.add(new TreeSet<Object>());
} else {
for (Object obj : sets[index]) {
for (Set<Object> set : _cartesianProduct(index+1, sets)) {
set.add(obj);
ret.add(set);
}
}
}
return ret;
}
public static void main(String[] args) {
Map<String, Set<String> > dataMap = new HashMap<String, Set<String> >();
dataMap.put("A", new TreeSet<String>(Arrays.asList("a1", "a2")));
dataMap.put("B", new TreeSet<String>(Arrays.asList("b1", "b2")));
dataMap.put("C", new TreeSet<String>(Arrays.asList("c1", "c2")));
System.out.println(cartesianProduct(dataMap.values().toArray(new Set<?>[0])));
}
}
Is there a better approach to do the below in Java, without using external libraries.
I need to model group/child (tree like) structure of int (primitive). In Json
[{1,1}, {1,2}, {2,1},{3,1}]
I need to support addition/removal of elements (element is a pair {group, child} ) without duplication.
I am thinking of, keeping a data structure like.
ArrayList<HashMap<Integer,Integer>>
To add.
Iterate through ArrayList, check HashMap key and value against the value to insert, and insert if not exist.
To delete:
Iterate through ArrayList, check HashMap key and value against the value to delete, and delete if exist.
Is there a better data structure/approach with standard library.
As per one of the answer below, I made a class like this.
Please let me know anything to watchout. I am expecting (and going to try out) arraylist would handle add/remove correctly by using the equal method in KeyValue class. thanks.
static class KeyValue {
int groupPos;
int childPos;
KeyValue(int groupPos, int childPos) {
this.groupPos = groupPos;
this.childPos = childPos;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KeyValue keyValue = (KeyValue) o;
if (childPos != keyValue.childPos) return false;
if (groupPos != keyValue.groupPos) return false;
return true;
}
#Override
public int hashCode() {
int result = groupPos;
result = 31 * result + childPos;
return result;
}
}
If I understand what you're trying to do, this may be simpler:
TreeMap<Integer,TreeSet<Integer>>
or
HashMap<Integer,HashSet<Integer>>
So, rather than
[{1,1}, {1,2}, {2,1}, {3,1}]
you'd have
[{1, {1, 2}},
{2, {1}},
{3, {1}}]
Note that all 4 of the above classes automatically handles eliminating duplicates.
To add:
TreeMap<Integer, TreeSet<Integer>> map;
TreeSet<Integer> set = map.get(group);
if (set == null) // create it if it doesn't exist
{
set = new TreeSet<Integer>();
map.put(group, set);
}
set.add(child);
To remove:
TreeMap<Integer, TreeSet<Integer>> map;
TreeSet<Integer> set = map.get(group);
set.remove(child);
if (set.isEmpty()) // remove it if it is now empty
map.remove(group);
You may write a class with name KeyValue with two properties to hold group and child. Add KeyValue Objects to ArrayList. For CRUD operations, you may implement equals and compare in your KeyValue pair class.
Instead of HashMap, use a class called Pair with two fields {group,child} which will implement Comparable interface. Then implement/override its equals(), hashCode() and compareTo() methods. Then use either a List<Pair> or Set<Pair> depending on your needs to hold them. Having compareTo() implemented gives you the flexibility to sort Pairs easily too.
I am new to the Data Structure world but I think we can use this based on the assumption that no two Set Objects will be similar
Set validSet=new HashSet(); // Use Generics here
HashSet will provide a constant time for add/delete/contains
SomeObject{
Integer parent ;
Integer child;
//define equals method based on your requirement
}
Going By your Question i think that You want to show this line
[{1,1}, {1,2}, {2,1},{3,1}]
as
Group 1-> 1 , 2 (from first two pair) Group 2-> 1(from
third pair) Group 3-> 1 (from fourth pair)
The data structure that suites most for storing this hierarchy is :
Map<Integer,Set<Integer>> map = new HashMap<Integer,Set<Integer>>();
Where the key part of map stores the group Number. And the value part of map is storing TreeSet which stores the children of that group.
As Example of code:
import java.util.HashMap;
import java.util.ListIterator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
class TreeLike
{
public static void main(String[] args)
{
Map<Integer,Set<Integer>> map = new HashMap<Integer,Set<Integer>>();
int groups[] = {1,2,3,4,5,6,7};
//To add new group in map
for (int i = 0 ; i < groups.length; i++)
{
Set<Integer> child = new TreeSet<Integer>();
child.add(1);child.add(2);child.add(3);child.add(4);child.add(5);
map.put(groups[i],child);
}
//To add new child(8) to a group (say group 1)
Set<Integer> child = map.get(1);
if (child != null)
{
child.add(8);
map.put(1,child);
}
//To remove a child (say child 4) from group 3
child = map.get(3);
if (child != null)
{
child.remove(4);
map.put(1,child);
}
//To Iterate through all trees
Set<Map.Entry<Integer,Set<Integer>>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer,Set<Integer>>> iterator = entrySet.iterator();
while (iterator.hasNext())
{
Map.Entry<Integer,Set<Integer>> entry = iterator.next();
int group = entry.getKey();
Set<Integer> children = entry.getValue();
System.out.println("Group "+group+" children-->"+children);
}
}
}
I have a List of Strings and I'm trying to have a method that tells me which String has more occurrences in the List.
Here is what I've done so far:
package codekata;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OcurrenciasEnLista {
public static void main(String[] args) {
List<String> lista = new ArrayList<String>();
lista.add("test");
lista.add("foo");
lista.add("foo");
lista.add("foo");
lista.add("bar");
lista.add("crack");
moreOftenWord(lista);
}
private static void moreOftenWord(List<String> lista) {
Map<String, Integer> mapa = new HashMap<String, Integer>();
for (String palabra: lista)
addOrIncrementCount(mapa, palabra);
}
private static void addOrIncrementCount(Map<String, Integer> counters,
String toAdd) {
Integer currValue = counters.get(toAdd);
if (currValue == null)
counters.put(toAdd, 1);
else
{
counters.put(toAdd, currValue + 1);
}
}
}
What I don't know how to do is to return -the word- already in the moreOftenWord method.
Can anybody give me a clue on this?
The most common element in a list is called the "mode" of the list.
http://www.dreamincode.net/forums/topic/39745-get-mode-of-a-list/ is the first result for "mode of a list java" that looks relevant in case you want a code sample.
To get at the most common element after you've built your map of counters, you probably want to do something like
Map.Entry<String, Integer> mode = null;
for (Map.Entry<String, Integer> e : counters.entrySet()) {
if (mode == null || mode.value() < e.value()) {
mode = e;
}
}
// Most common string in mode.getKey()
This assumes that you redefine
Map counters
generically as
Map<String, Integer> counters
The Multiset data structure maintains a count of each element added to it. So you can remove all boilerplate code if you use this. Then all you need to do is iterate through the Multiset and find the element that has the max count.
Guava library has many such useful data structures and more.
In statistics, this is called the "mode" (as Mike's answer already explained). jOOλ is a library that supports mode() on streams. The following program:
System.out.println(
Seq.of("test", "foo", "foo", "foo", "bar", "crack")
.mode()
);
Yields:
Optional[foo]
(disclaimer: I work for the company behind jOOλ)
I am getting this strange output in HashMap.
I have two ArrayList<String> one containing the key and another containing value.
My HashMap<String,String> will store only string as key and value pair. But key itself is getting stored in value. I have checked my value arraylist, it's printing the value. But during putting it's setting it as key itself.
Code snippet is:
public HashMap<String,String> getLstBarring()
{
ArrayList<String> temparrLst=setPreParameters(fetchPreDetails, 1);
System.out.println("KEY" + temparrLst);
ArrayList<String> tempArrLstId=setPreParameters(fetchPreDetails, 14);
System.out.println("VALUE" +tempArrLstId);
int length=tempArrLstId.size();
for(int index=0;index<length;index++)
{
System.out.println("VALUE IN KEY" + temparrLst.get(index));
System.out.println("VALUE IN VALUE" + tempArrLstId.get(index));
this.lstBarring.put(temparrLst.get(index), tempArrLstId.get(index));
}
System.out.println("INSIDE ODB....>>>>>>>>>>>>>>" + lstBarring);
return this.lstBarring;
}
Problem is:
1st SOP is KEY-printing all the key correctly.
2nd SOP is VALUE-printing all the value correctly.
3rd SOP is VALUE IN KEY----printing all the values.
4th SOP is VALUE IN VALUE--printing all the values.
Hence after ever iteration I am getting value,value in HashMap whereas it should be key,value.
Here's look at my Method:-
public ArrayList<String> setPreParameters(HashMap<Integer,String> fetchPreDetails,int index)
{
switch(index)
{
case 1:
{
arrLstData.clear();
splittedString=fetchPreDetails.get(1).split(",");
Collections.addAll(arrLstData, splittedString);
break;
}
return arrLstData;
Please guide me as to where am I going wrong.
My guess is that either fetchPreDetails is a collection being mutated by setPreParameters() or else setPreParameters() is mutating some other shared state so that the collection referenced by your temparrLst is being changed on the second call to setPreParameters(). I.e.
List<String> strings = new ArrayList();
strings.add("a");
strings.add("b");
List<String> otherStrings = strings;
otherStrings.add("c");
I expect your code assumes that strings would contain "a" and "b" and that otherStrings would contain "a", "b", and "c". This isn't how object references work in Java. The line List<String> otherStrings = strings; makes both strings and otherStrings point to the same collection, and thus changes made using either name affect the same thing.
Edit: Your newly-posted code seems to prove my hypothesis. You have a variable called arrLstData that you clear, populate, and return on each call to setPreParameters(). You're returning the same collection every time you call this method. Therefore you just have multiple handles to the same collection instead of multiple collections. You need to create a new collection and return it each time you call setPreParameters().
Edit again: Maybe this will make it clearer. Here's what you're doing:
public static void main(String[] args) {
Foo f = new Foo();
List<String> list1 = f.getList("a", "b");
System.out.println(list1);
List<String> list2 = f.getList("c", "d");
System.out.println(list2);
System.out.println(list1);
}
static class Foo {
private List<String> myList = new ArrayList<String>();
public List<String> getList(String... strings) {
myList.clear();
myList.addAll(Arrays.asList(strings));
return myList;
}
}
Note that this exhibits exactly the behavior that you're describing, and the correct way to solve it is something like this:
public static void main(String[] args) {
Foo f = new Foo();
List<String> list1 = f.getList("a", "b");
System.out.println(list1);
List<String> list2 = f.getList("c", "d");
System.out.println(list2);
System.out.println(list1);
}
static class Foo {
public List<String> getList(String... strings) {
List<String> result = new ArrayList<String>();
result.addAll(Arrays.asList(strings));
return result;
}
}
You are reusing the same List over and over at your setPreParameters Method.
The List in arrLstData is returned and stored in temparrLst, now you are clearing the the Lists content, putting new stuff in it and storing it to tempArrLstId.
Now the three variables all contain the very same list (they are not equals, its the same!).
There is only one List object at the whole example!
Its like you got a box and label it "A" on one side put stuff in it, label it "B" on another side and wondering why the box "B" is empty when you turn box "A" upside-down.
Did you maybe mean something like this?
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GlobalsMess {
private Map<String, String> lstBarring = new HashMap<String, String>();
private Map<Integer, String> fetchPreDetails = new HashMap<Integer, String>();
public GlobalsMess() {
fetchPreDetails.put(1, "john,vikam,david");
fetchPreDetails.put(14, "1,2,3");
}
public Map<String, String> getLstBarring() {
List<String> tempKeys = setPreParameters(fetchPreDetails.get(1));
System.out.println("KEY" + tempKeys);
List<String> tempIds = setPreParameters(fetchPreDetails.get(14));
System.out.println("VALUE" + tempIds);
for (int index = 0; index < tempIds.size(); index++) {
System.out.println("VALUE IN KEY" + tempKeys.get(index));
System.out.println("VALUE IN VALUE" + tempIds.get(index));
this.lstBarring.put(tempKeys.get(index), tempIds.get(index));
}
System.out.println("INSIDE ODB....>>>>>>>>>>>>>>" + lstBarring);
return this.lstBarring;
}
public List<String> setPreParameters(String fetchPreDetailsValue) {
List<String> arrLstData = new ArrayList<String>();
Collections.addAll(arrLstData, fetchPreDetailsValue.split(","));
return arrLstData;
}
public static void main(String[] args) {
new GlobalsMess().getLstBarring();
}
}
Output:
KEY[john, vikam, david]
VALUE[1, 2, 3]
VALUE IN KEYjohn
VALUE IN VALUE1
VALUE IN KEYvikam
VALUE IN VALUE2
VALUE IN KEYdavid
VALUE IN VALUE3
INSIDE ODB....>>>>>>>>>>>>>>{david=3, vikam=2, john=1}