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;
}
Related
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 am trying to get friends recommendations for a user based on their direct friends and rank them on their frequency(i.e number of times the recommended friend appeared on user's direct friend lists). Below is the working code to solve the problem.
public List<String> getFriendsRecommendations(String user)
{
Recommendations rd = new Recommendations();
List<String> result= new ArrayList<String>();
List<String> drfriend = rd.getdirectfriends(user); //return list of direct friend for the user.
List<ArrayList<String>> allfriends = new ArrayList<ArrayList<String>>();
Map<String, Integer> mapfriend = new HashMap<String, Integer>();
List<String> userfriend = rd.getfriends(user); //returns the list of all the friends for a given user.
int counter =0;
for(String s: drfriend)
{
allfriends.add(new ArrayList<String>(rd.getfriends(s)));
rd.intersection(userfriend, allfriends.get(counter), mapfriend);
counter++;
}
result.addAll(mapfriend.keySet());
//Sorting based on the value of hashmap. friend with highest value will be recommended first
Collections.sort(result, new Comparator<String>(){
public int compare(String s1, String s2)
{
if(mapfriend.get(s1) > mapfriend.get(s2))
return -1;
else if(mapfriend.get(s1) < mapfriend.get(s2))
return 1;
else if(mapfriend.get(s1) == mapfriend.get(s2))
{
return s1.compareTo(s2);
}
return 0;
}
});
return result;
}
public void intersection(List<String> lt1, ArrayList<String> lt2, Map<String, Integer> ranked)
{
lt2.removeAll(lt1); // ignoring the friends that user is already connected to
for(String st: lt2)
{
boolean val = ranked.containsKey(st);
if(val)
{
int getval = ranked.get(st);
ranked.put(st, getval+1); //friend name as a key and the value would be the count.
}
else
{
ranked.put(st, 1);
}
}
}
I would like to know if there is more efficient way to solve the above problem instead of using 2 for loops?
Quick tip for your Comparator: Get the two values you are interested in comparing at the start and store them in variables, that way you only do a maximimum of 2 get calls instead of 6 in your current worst case scenario (each get call will hash the String, so less is better).
As for simplifying the for loops, could you just get a list of friends of friends and count the occurrences of each friend in that list? Then afterwards, remove any friends you are already friends with.
I have a list of strings and list of objects(SomeObject). Every SomeObject will have a list of other objects(SecondaryObject) and that object will have a string property. I need to check if the string property is in the first list.
List<String> stringList = new ArrayList<>(Arrays.asList("String1", "String2"));
List<SomeObject> objectList;
public class SomeObject {
public List<SecondaryObject> secondaryList;
}
public class SecondaryObject {
public String str;
}
for (String mainString : stringList) {
for (SomeObject obj : objectList) {
List<SecondaryObject> secobjList = obj.getSecList();
for (SecondaryObject secObj : secObjList) {
if (secObj.str.equals(mainString)) {
log.log("Found a match");
}
}
}
}
Is there any optimal solution than this.
I would suggest you to make use of hashing. Make a hashMap of stringList then you don't need a third loop. Instead for every secObj's string property just try to get it's value from map, if it does'nt return null then your match is found.
HashMap<String, Integer> map = new HashMap<String, Integer>();
for(String mainString: stringList){
map.put(mainString, 1);
}
for (SomeObject obj : objectList) {
List<SecondaryObject> secobjList = obj.getSecList();
for (SecondaryObject secObj : secObjList) {
if (map.get(secObj.str) != null) {
log.log("Found a match");
}
}
}
From O(n^3) reduced to O(n^2)
If you are not sure if the string property inside any SecondaryObject is unique across the list of SecondaryObject inside SomeObject then I would suggest starting by collating that String in a Set.
The goal is to transform this problem of finding the intersection of two lists of strings.
Then this problem can be solved in two ways
Iterate through the stringList and search for that string in the other list. If you sort that list first the searching can be faster
This is an optimization to approach 1 where you both the lists and then use the longest common subsequence algorithm (https://en.wikipedia.org/wiki/Longest_common_subsequence_problem)
At first I had something like this:
public static boolean equals(TreeMap<?, Boolean> a, TreeMap<?, Boolean> b) {
boolean isEqual = false;
int count = 0;
if (a.size() == b.size()) {
for (boolean value1 : a.values()) {
for (boolean value2 : b.values()) {
if (value2 == value1) {
count++;
isEqual = true;
continue;
} else {
isEqual = false;
return isEqual;
}
}
}
if (count == a.size()) {
return true;
}
}
}
Then found that nope it didn't work. I'm checking to see if every element in Object a is the same as in Object b without using Iterate or Collection. and in the same place... any suggestions? Would implementing a for-each loop over the keySet() work?
So, something along these lines? Needing to take in account BOTH keys and values: (Not an answer - test code for suggestions)
This should work as values() are backed up by the TreeMap, so are sorted according to the key values.
List<Boolean> aList = new ArrayList<>(a.values());
List<Boolean> bList = new ArrayList<>(b.values());
boolean equal = aList.equals(bList);
This should be a bit faster than a HashSet version.
And this won't work as #AdrianPronk noticed:
a.values().equals(b.values())
How about this :
Set values1 = new HashSet(map1.values());
Set values2 = new HashSet(map2.values());
boolean equal = values1.equals(value2);
For Comparing two Map Objects in java, 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.
The correct way to compare maps is to:
Check that the maps are the same size(!)
Get the set of keys from one map
For each key from that set you retrieved, check that the value retrieved from each map for that key is the same
I know the differences between Set and List(unique vs. duplications allowed, not ordered/ordered, etc). What I'm looking for is a set that keeps the elements ordered(that's easy), but I also need to be able to recover the index in which an element was inserted. So if I insert four elements, then I want to be able to know the order in which one of them was inserted.
MySet<String> set = MySet<String>();
set.add("one");
set.add("two");
set.add("three");
set.add("four");
int index = set.getIndex("two");
So at any given moment I can check if a String was already added, and get the index of the string in the set. Is there anything like this, or I need to implement it myself?
After creating Set just convert it to List and get by index from List:
Set<String> stringsSet = new HashSet<>();
stringsSet.add("string1");
stringsSet.add("string2");
List<String> stringsList = new ArrayList<>(stringsSet);
stringsList.get(0); // "string1";
stringsList.get(1); // "string2";
A small static custom method in a Util class would help:
public static <T> int getIndex(Set<T> set, T value) {
int result = 0;
for (T entry:set) {
if (entry.equals(value)) return result;
result++;
}
return -1;
}
If you need/want one class that is a Set and offers a getIndex() method, I strongly suggest to implement a new Set and use the decorator pattern:
public class IndexAwareSet<T> implements Set {
private Set<T> set;
public IndexAwareSet(Set<T> set) {
this.set = set;
}
// ... implement all methods from Set and delegate to the internal Set
public int getIndex(T entry) {
int result = 0;
for (T entry:set) {
if (entry.equals(value)) return result;
result++;
}
return -1;
}
}
you can extend LinkedHashSet adding your desired getIndex() method. It's 15 minutes to implement and test it. Just go through the set using iterator and counter, check the object for equality. If found, return the counter.
One solution (though not very pretty) is to use Apache common List/Set mutation
import org.apache.commons.collections.list.SetUniqueList;
final List<Long> vertexes=SetUniqueList.setUniqueList(new LinkedList<>());
it is a list without duplicates
https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.2/index.html?org/apache/commons/collections/list/SetUniqueList.html
How about add the strings to a hashtable where the value is an index:
Hashtable<String, Integer> itemIndex = new Hashtable<>();
itemIndex.put("First String",1);
itemIndex.put("Second String",2);
itemIndex.put("Third String",3);
int indexOfThirdString = itemIndex.get("Third String");
you can send your set data to a new list
Java ArrayList<String> myList = new ArrayList<>(); myList.addAll(uniqueNameSet); myList.indexOf("xxx");