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;
}
}
Related
Description
I have a HashMap<ArrayLists<Integer>, <Integer>>, similar to the following ({Key=Value}):
{[1]=1, [3]=1, [1, 4, 6]=1, [0, 2, 3, 5, 6]=3, [6]=1}
I need to compare and then modify/remove elements in different ArrayLists (i.e., elements in the HashMap), until the following conditions are met:
Each ArrayList element only belongs to one list, the list with the highest Value.
If Value = 1 for all lists containing that element, then the ArrayList element belongs to the singleton list.
If an ArrayList becomes empty, then it should be removed from the HashMap.
Thus for the example above, it should end up with the following:
{[1]=1, [4]=1, [0, 2, 3, 5, 6]=3}
I am used to work with arrays of arrays to do stuff like this. This time it would be practical to have the features of HashMap and ArrayList, but I am currently not comfortable to do more complicated modification of these data types. I have done several attempts and have had to prevent both ConcurrentModificationException and IllegalStateException, but have yet to succeed fully. I also have a feeling my implementations are getting unnecessary complex, so I would greatly appreciate to see an implementation by someone experienced with things like this.
A Note About The HashMap
The reason I use a HashMap (feel free to suggest something more appropriate) is that the Value is a count of how many times the ArrayList has been "encountered" and added to the HashMap.
Minimal Example
Minimal example of my latest non-working (IndexOutOfBoundsException) attempt. Note that the creation of the HashMap and ArrayLists is done statically here since in my real program it is done non-deterministically based on file contents.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<List<Integer>, Integer> example = new HashMap<>(7);
List<Integer> list = new ArrayList<>(7);
list.add(1);
example.put(list, 1);
list = new ArrayList<>(7);
list.add(3);
example.put(list, 1);
list = new ArrayList<>(7);
list.add(1);
list.add(4);
list.add(6);
example.put(list, 1);
list = new ArrayList<>(7);
list.add(0);
list.add(2);
list.add(3);
list.add(5);
list.add(6);
example.put(list, 3);
list = new ArrayList<>(7);
list.add(6);
example.put(list, 1);
System.err.println(example);
Map<List<Integer>, Integer> copy = new HashMap<>(example);
for (Map.Entry<List<Integer>, Integer> outer : example.entrySet()) {
for (Map.Entry<List<Integer>, Integer> inner : copy
.entrySet()) {
for (int i : outer.getKey()) {
int oSize = outer.getKey().size();
int iSize = inner.getKey().size();
int oValue = outer.getValue();
int iValue = inner.getValue();
if (!(inner.equals(outer)) && (inner.getKey()
.contains(i))) {
if (oSize == 1) {
if (oValue < iValue) {
outer.getKey().remove(i);
} else {
inner.getKey().remove(i);
}
} else if (iSize == 1) {
if (iValue < oValue) {
outer.getKey().remove(i);
} else {
inner.getKey().remove(i);
}
} else {
if (oValue < iValue) {
outer.getKey().remove(i);
} else {
inner.getKey().remove(i);
}
}
}
}
}
}
}
}
Its highly unusual to use an ArrayList as the key to a HashMap (Are mutable hashmap keys a dangerous practice?).
But assuming you are okay with this, to update a Map entry you could remove the entry(both the List and the integer) from the hasmap, create a new List that has your changes, and then reinsert if necessary.
In my poor opinion, I suggest order the map value (according to the highest value) in 1st round, then complete our deletion work with business logic.
For example:
Map<List<Integer>, Integer> example = new HashMap<>();
// data initialize
// order by Map.Entry::getValue desc
List<Map.Entry<List<Integer>, Integer>> collect = example.entrySet()
.stream()
.sorted((e1, e2) -> e2.getValue() - e1.getValue())
.collect(Collectors.toList());
// remove duplicate list element in Map.Entry::getKey
Set<Integer> tmp = new HashSet<>();
// collect.forEach(c -> c.getKey().removeIf(next -> !tmp.add(next)));
example = collect
.stream()
.filter(c -> {
c.getKey().removeIf(next -> !tmp.add(next));
return !c.getKey().isEmpty();
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Below is the program which has hashmap and adding list as keys. However duplicate list are being added. Now i want to remove all the duplicate list inside residing as values.
import java.util.*;
public class Test {
public static void main(String args[]) {
Map<String, List<Integer>> sample = new HashMap<String, List<Integer>>();
List first = new ArrayList();
first.add(1);
first.add(2);
first.add(3);
List second = new ArrayList();
second.add(4);
second.add(5);
second.add(6);
List third = new ArrayList();
third.add(1);
third.add(2);
third.add(3);
sample.put("first", first);
sample.put("second", second);
sample.put("third", third);
System.out.print(sample.size()); // Prints 3
// Need to Remove the duplicate lists
// Expects two keys with list first and second since third is duplicate value
// 1,23 and 4,5,6 instead of 1,2,3 4,5,6 and 1,2,3
}
}
May be this piece of code will work for you -
public static void main(String[] args) {
Map<String, List<Integer>> sample = new HashMap<String, List<Integer>>();
List first = new ArrayList();
first.add(1);
first.add(2);
first.add(3);
List second = new ArrayList();
second.add(4);
second.add(5);
second.add(6);
List third = new ArrayList();
third.add(1);
third.add(2);
third.add(3);
sample.put("first", first);
sample.put("second", second);
sample.put("third", third);
removeDuplicates(sample);
System.out.print(sample.size()); // now it will print 2
}
private static void removeDuplicates(Map<String, List<Integer>> sample) {
Collection<List<Integer>> list = sample.values();
for(Iterator<List<Integer>> itr = list.iterator(); itr.hasNext();) {
if(Collections.frequency(list, itr.next())>1) {
itr.remove();
}
}
}
This remove duplicate method will remove the duplicate values from the List.
I want to compare keys of two different arraylists say
List<DataSt> list1 = new ArrayList<DataSt>();
List<DataSt> list2= new ArrayList<DataSt>();
DataSt is:
public class DataSt {
public String key;
BigDecimal time;
BigDecimal memory;
public DataSt(String key,BigDecimal time, BigDecimal memory)
{
this.key=key;
this.time=time;
this.memory=memory;
}
}
list1:
<org.openjdk.jmh.samples.JMHSortBenchmark.collectionsSort,6691.679,5454>
<org.openjdk.jmh.samples.JMHSortBenchmark.abcdSort,5151.45,54545>
<org.openjdk.jmh.samples.JMHSortBenchmark.saasSort,5454.54,21212.2>
<org.openjdk.jmh.samples.JMHSortBenchmark.xyzSort,888.22,2115>
list2:
<org.openjdk.jmh.samples.JMHSortBenchmark.xyzSort,7448.362,7887.2>
<org.openjdk.jmh.samples.JMHSortBenchmark.abcdSort,951.5,4512.5>
<org.openjdk.jmh.samples.JMHSortBenchmark.lmnSort,4454.54,455.2>
And if they match eg., "org.openjdk.jmh.samples.JMHSortBenchmark.xyzSort" so I want to return the <Key,time,memory> of both list1 and list2 i.e., it must return
org.openjdk.jmh.samples.JMHSortBenchmark.xyzSort,888.22,2115
org.openjdk.jmh.samples.JMHSortBenchmark.xyzSort,7448.362,7887.2
org.openjdk.jmh.samples.JMHSortBenchmark.abcdSort,5151.45,54545
org.openjdk.jmh.samples.JMHSortBenchmark.abcdSort,951.5,4512.5
because I want to process the difference between their values and compare them i.e., 888.2,2115 in list1 and 7448.362,7887.2 in map2 thereby logging the difference to a csv file.
I used the following code:
public static List<DataSt> outputComparator(List<DataSt> list1, List<DataSt> list2) {
List<DataSt> map4 = new ArrayList<DataSt> ();
for (DataSt entry: list1) {
if (list2.contains(entry.key)) {
saveRecord(entry, **//Here I want to return DataSt of list2//**,entry.key,map4);
} else {
saveRecord(entry.key, map4);
}
}
for (DataSt entry: list2) {
if (!(list1.contains(entry.key))) {
saveRecord(entry.key, map4);
}
}
return map4;
}
The "entry" in statement "saverecord" returns "list1.key, list1.time, list1.value" for that run
Here I am not sure how to get "DataSt part of list2". Can someone help me how do I retrive "list2.key, list2.time, list2.value" when "list1.key == list2.key" (Refer commented field in saveRecord()).
list2.contains(entry.key) doesn't do what you think it does. It has no idea that DataSt.key is actually a key. You are trying to match a String object to a DataSt object (which will never work).
You could override equals to just compare the keys or you could write your own DataSt findItem(ArrayList<DataSt> list, String key)
If you really need keyed data you could look into a different structure where you can actually lookup by key.
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;
}
}
I have an object as Riziv with three variables as id, cnk and product. Then I search in a databank for this object and add it to a ArrayList as ArrayList<Riziv> list.
Now I should checkout if all object in his array are the same cnk then return true otherwise I should return all objects which are not the same cnk with error message.
public class Riziv{ String id, cnk, product; }
ArrayList<Riziv> list = getArrayListFromDatabank(id);
public void getDuplicatedWhichHasTheSameCnk(){
}
}
Using standard JVM structures (MultiMap is provided by guava), you can do that:
public List<Riviz> getDuplicates(final List<Riviz> l)
{
final HashMap<String, List<Riviz>> m = new HashMap<String, List<Riviz>>();
final List<Riviz> ret = new ArrayList<Riviz>();
String cnk;
for (final Riviz r: l) {
cnk = r.getCnk();
if (!m.contains(cnk))
m.add(cnk, new ArrayList<Riviz>());
m.get(cnk).add(r);
}
List<Riviz> tmp;
for (final Map.Entry<String, List<Riviz>> entry: m.entrySet()) {
tmp = entry.getValue();
if (tmp.size() == 1) // no dups
continue;
ret.addAll(tmp);
}
return ret;
}
ret will contain the duplicates. You can change that function to return a Map<String, Riviz> instead, and filter out entries where the list size is only one. You'll then get a map with the conflicting cnks as keys and a list of dups as values.
I am not clear exactly what you want however I suspect you want something like this.
MultiMap<Key, Riziv> multiMap =
List<Riziv> list =
for(Riziv r: list)
multiMap.put(r.getCnk(), r);
for(Key cnk: multiMap.keySet()) {
Collection<Riziv> sameCnk = multiMap.get(cnk);
// check size and compare entries
}
The multi-map will have the list of Riziv objects for each Cnk.
One way to do it is write a comparator to sort the list by cnk String and then compare each consecutive cnk String to the next, if you find a duplicate, they will be right next to eachother.
1.) Sort the list using a comparator by sorting on the cnk variable.
2.) Compare each element in the list to the next for duplicates.
There's probably many other ways to solve this, this is just the first that came to mind.
I did not test this so you have been forewarned lol:
ArrayList<Riziv> rizArray = new ArrayList<Riziv>();
//Sort the array by the CNK variable.
Collections.sort(rizArray, new Comparator<Riziv>(){
#Override
public int compare(Riziv arg0, Riziv arg1) {
//Return the comparison of the Strings.
//Use .compareToIgnoreCase if you want to ignore upper/lower case.
return arg0.getCnk().compareTo(arg1.getCnk());
}
});
//List should be in alphabetical order at this point.
List<Riziv> duplicates = new ArrayList<Riziv>();
Riziv rizPrevious = null;
for(Riziv riz: rizArray){
if(rizPrevious == null){
rizPrevious = riz;
continue;
}
if(riz.getCnk().compareTo(rizPrevious.getCnk()) == 0){
duplicates.add(riz);
}
rizPrevious = riz;
}