I have a global variable masterList, which is a HashMap.
private static HashMap<ArrayList<String>, Integer> masterList =
new HashMap<ArrayList<String>, Integer>();
I have a recursive function, generateAnagram that puts ArrayLists of anagrams in this HashMap with the number of words in the list as the value. However, the HashMap starts to mess up after the first call,and previous ArrayLists are overriden with the new one I'm trying to add, but the previous value remains. This results in two keys with the same value.
Here's a screenshot of the results - Click [here] http://tinypic.com/r/ka1gli/8
private static void generateAnagram(Set<String> subsets, ArrayList<String> currList, letterMap wordMap) {
if (wordMap.count() == 0) {
System.out.println("Adding: " + currList);
masterList.put(currList, currList.size());
System.out.println("Current Master: " + masterList.toString());
} else {
for (String word : subsets) {
if (word.length() <= wordMap.count() && wordMap.isConstructionPossible(word)) {
//System.out.println("Word: " + word + " " + wordMap.isConstructionPossible(word));
wordMap.remove(word);
currList.add(word);
generateAnagram(subsets, currList, wordMap);
currList.remove(word);
wordMap.addBack(word);
}
}
}
}
It's not a good idea to use an ArrayList as the key of a HashMap. Each time you change the content of the ArrayList (by adding or removing elements), its hashCode would change, so even if it's already in the HashMap, get() and containsKey() won't find it, and put() will add it again.
You only have one instance of the ArrayList, which you keep putting in the masterList map, so you would have only one entry in your map if you didn't change the contents of that list all the time.
You need to look at this from the point of view of the parameters. The ArrayList reference is passed as an argument to your recursion call each time, but it still points to the same ArrayList. When you then put it into the hashmap, you are storing multiple references to the same, single, original ArrayList.
Therefore use ArrayList.clone() before adding it to the master list. Better still, store an immutable collection to ensure your hash doesn't get messed up in the HashMap:
HashMap<List<String>, Integer> masterList =
new HashMap<List<String>, Integer>();
...
ArrayList<String> tmp = (ArrayList<String>)currList.clone();
List<String> imm = Collections.unmodifiableList(tmp);
masterList.put(imm, imm.size());
"previous ArrayLists are overriden with the new one I'm trying to add, but the previous value remains."
If you do not want the previous values, you might need to do something like this
BEFORE SCENARIO:
final ArrayList<Integer> arrayList = new ArrayList<Integer>();
final HashMap<ArrayList<Integer>, Integer> hashmap = new HashMap<ArrayList<Integer>, Integer>();
arrayList.add(1);
hashmap.put(arrayList, 1);
arrayList.add(2);
hashmap.put(arrayList, 1);
System.out.println(hashmap);
OUTPUT : {[1, 2]=1, [1, 2]=1}
AFTER SCENARIO :
ArrayList<Integer> arrayList = new ArrayList<Integer>();
final HashMap<ArrayList<Integer>, Integer> hashmap = new HashMap<ArrayList<Integer>, Integer>();
arrayList.add(1);
hashmap.put(arrayList, 1);
arrayList = new ArrayList<Integer>();
arrayList.add(2);
hashmap.put(arrayList, 1);
System.out.println(hashmap);
OUTPUT : {[1]=1, [2]=1}
Related
I have a new ArrayList inside a HashMap, but i don't know how to calculate the size of ArrayList inside the HashMap
Map<String, List<fruit>> groupbyregion = new HashMap<>();
for (fruit s : ll) {
if (!groupbyregion.containsKey(s.getRegionName())) {
groupbyregion.put(s.getRegionName(), new ArrayList<>());
}
groupbyregion.get(s.getRegionName()).add(s);
}
System.out.println("Group by region: " + groupbyregion);
You are already using:
groupbyregion.get(s.getRegionName()).add(s);
This calls the add() method of the ArrayList in that map slot.
Thus:
groupbyregion.get(s.getRegionName()).size();
gives you the size.
Beyond that: you want to look here for how to create lists within maps in more elegant (java8) ways.
noob here, so sorry if I say anything dumb.
I'm comparing strings in an ArrayList to an iterator of strings in an iterator of Sets. When I find a match, I want to grab the index of matched string in the ArrayList and increment that same index in a different ArrayList of integers. I have something that looks (to me) like it should work, but after this code runs, my integer ArrayList contains mostly -1 with a few 2,1, and 0.
I'm interested in fixing my code first, but I'd also be interested different approaches, so here's the larger picture: I have a map where the keys are usernames in a social network, and the values are sets usernames of people they follow. I need to return a list of all usernames in descending order of followers. In the code below I'm only trying to make an ArrayList of strings (that contains ALL the usernames in the map) that correspond with a different ArrayList of integers like:
usernamesList ... numberOfFollowers
theRealJoe ... 7
javaNovice ... 3
FakeTinaFey ... 3
etc
Map<String, Set<String>> map = new HashMap<String, Set<String>>();
//edit: this map is populated. It's a parameter of the method I'm trying to write.
List<String> usernamesList = new ArrayList<String>();
//populate usernamesList with all strings in map
Iterator<Set<String>> setIter = map.values().iterator();
Iterator<String> strIter;
int strIterIndex = 0;
int w = 0;
List<Integer> numOfFollowers = new ArrayList<Integer>();
//initialize all elements to 0. not sure if necessary
for (int i = 0; i < usernamesList.size(); i++) {
numOfFollowers.add(0);
}
while (setIter.hasNext()) {
Set<String> currentSetIter = setIter.next();
strIter = currentSetIter.iterator();
while (strIter.hasNext()) {
String currentstrIter = strIter.next();
if (usernamesList.contains(currentstrIter)) {
strIterIndex = usernamesList.indexOf(currentstrIter);
numOfFollowers.set(strIterIndex, numOfFollowers.indexOf(strIterIndex) +1);
w++;
System.out.println("if statement has run " + w + " times." );
} else {
throw new RuntimeException("Should always return true. all usernames from guessFollowsGraph should be in usernamesList");
}
}
}
I think everyhing looks ok, except this one:
numOfFollowers.set(strIterIndex, numOfFollowers.indexOf(strIterIndex) +1);
When you do numOfFollowers.indexOf, you are looking for the index of an element that has a value strInterIndex. What you want, is the value (follower count) of an element with index strIterIndex:
numOfFollowers.set(strIterIndex, numOfFollowers.get(strIterIndex) +1);
I would also suggest using int[] (array) instead of a list of indices. It would be faster and more straightforward.
Oh, one more thing: correct the "fake" constructors please, they won't work since there is no "new" keyword after the assignment...
public class ListMap {
HashMap<Integer, List> mp = new HashMap();
List myList = new ArrayList();
Integer x = 0;
Integer y = 5;
void test() {
for(Integer i = 0; i < 5; i++) {
x = y;
myList.add("check-1a" + i);
myList.add("check-1a" + i + 1);
y = null;
System.out.println(x); // output=5
mp.put(i, myList);
myList.clear();
}
}
1) But after clearing the List with myList.clear() the values that was inside the Map also gets cleared.
I mean to say that the map key remains there but it contains an "empty" List
2) However regarding the Objects x & y, after setting y to null how come x doesn't change?
When you add an object to a map (or any other collection), you are adding a reference to that object, not a copy. When you then make changes to the object, these changes will also affect the references in the map.
When you want to store a copy of your list, you need to create a new one. This can be done like this:
mp.put(i, new ArrayList(myList));
An alternative (and in my opinion even better) solution would be to reinitialize myList in the beginning of each loop iteration by setting it to a fresh list object:
myList = new ArrayList();
myList.add("check-1a"+i);
myList.add("check-1a"+i+1);
mp.put(i,myList);
Note that the list doesn't get destroyed when you reinitialize the variable myList. You can think of the object living on inside the map*.
*although a more technically accurate description would be "the object lives on in memory and isn't garbage-collected as long as there is still a reference to it stored in the map"
You're adding the same list to the Map multiple times and clearing it each time, so no surprise that its empty. Solution: Don't clear the list, create a new one within the for loop. This way, the Map will hold a unique List for each Integer.
public class ListMap {
HashMap<Integer,List<String>> mp=new HashMap<>();
// List<String> myList=new ArrayList<String>(); // **** get rid of
Integer x=0;
Integer y=5;
void test(){
for(Integer i=0;i<5;i++){
List<String> myList=new ArrayList<String>(); // ****** here
x=y;
myList.add("check-1a"+i);
myList.add("check-1a"+i+1);
y=null;
System.out.println(x);//output=5
mp.put(i,myList);
// myList.clear(); // **** get rid of
}
}
Also as per Tom, don't use raw types if possible, and so declare your lists as List<String> and ArrayList<String>.
I have a list of words which contains multiple duplicate words. I want to extract the words that are duplicated and store them in another list (maintaining the integrity of the original list).
I tried iterating through the list like you see below, but this fails logically because every 'dupe' will at some point be equal to primary. I really want to iterate through the list and for every String in the list check all the OTHER strings in the list for duplicates.
Is there a method in the List interface that allows this type of comparison?
For reference list 1 is a list of Strings.
for(String primary: list1){
for(String dupe: list1){
if(primary.equals(dupe)){
System.out.print(primary + " " + dupe);
ds3.add(primary);
}
}
}
EDIT:
I should note, that I'm aware that a Set doesn't allow for duplicates, but what I'm trying to do is OBTAIN the duplicates. I want to find them, and take them out and use them later. I'm not trying to eradicate them.
The easiest way to remove the duplicates is to add all elements into a Set:
Set<String> nodups = new LinkedHashSet<String>(list1);
List<String> ds3 = new ArrayList<String>(nodups);
In the above code, ds3 will be duplicate-free. Now, if you're interested in finding which elements are duplicate in O(n):
Map<String, Integer> counter = new LinkedHashMap<String, Integer>();
for (String s : list1) {
if (counter.containsKey(s))
counter.put(s, counter.get(s) + 1);
else
counter.put(s, 1);
}
With the above, it's easy to find the duplicated elements:
List<String> ds3 = new ArrayList<String>();
for (Map.Entry<String, Integer> entry : counter.entrySet())
if (entry.getValue() > 1)
ds3.add(entry.getKey());
Yet another way, also O(n): use a Set to keep track of the duplicated elements:
Set<String> seen = new HashSet<String>();
List<String> ds3 = new ArrayList<String>();
for (String s : list1) {
if (seen.contains(s))
ds3.add(s);
else
seen.add(s);
}
Consider using a Set. "A collection that contains no duplicate elements."
The intent is to extract the duplicates not lose them entirely
List<String> list =
Set<String> set = new LinkedHashSet<>(); // to keep he order
List<String> dups = new ArrayList<String>(); // could be duplicate duplicates
for(String s: list)
if (!set.add(s)) dups.add(s);
To obtain only the duplicates (as opposed to eliminating duplicates from the list), you can use a set as a temporary lookup table of what previous string has been visited:
Set<String> tmp = new HashSet<String>();
for(String primary: list1){
if(tmp.contains(primary)) {
// primary is a duplicate
}
tmp.add(primary);
}
My problem is as follows. I have an arraylist of integers. The arraylist contains 5 ints e.g[5,5,3,3,9] or perhaps [2,2,2,2,7]. Many of the arraylists have duplicate values and i'm unsure how to count how many of each of the values exist.
The problem is how to find the duplicate values in the arraylist and count how many of that particular duplicate there are. In the first example [5,5,3,3,9] there are 2 5's and 2 3's. The second example of [2,2,2,2,7] would be only 4 2's. The resulting information i wish to find is if there are any duplicates how many of them there are and what specific integer has been duplicated.
I'm not too sure how to do this in java.
Any help would be much appreciated. Thanks.
To me, the most straightforward answer, would be using the Collections.frequency method. Something along the lines of this:
// Example ArrayList with Integer values
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(2);
intList.add(2);
intList.add(2);
intList.add(2);
intList.add(7);
Set<Integer> noDupes = new HashSet<Integer>();
noDupes.addAll(intList); // Remove duplicates
for (Integer i : noDupes) {
int occurrences = Collections.frequency(intList, i);
System.out.println(i + " occurs " + occurrences + " times.");
}
If you want to, you could map each Integer with its number of occurrences:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer i : noDupes) {
map.put(i, Collections.frequency(intList, i));
}
Two algorithms spring to mind.
Sort it (Collections.sort). Then iterate through easily finding dupes.
Iterate through keeping count in a Map<Integer,Integer> (or Map<Integer,AtomicInteger> for a mutable count). A bit ugly this way.
Either way, coding it should be an instructive exercise. I suggest doing both, and comparing.
Here is a concrete implementation, with test, of what I described in comments to #Tom's answer:
package playground.tests;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.TestCase;
public class DupeCounterTest extends TestCase {
public void testCountDupes() throws Exception {
int[] array = new int[] { 5, 5, 3, 3, 9 };
assertEquals("{3=2, 5=2}", countDupes(array).toString());
}
private Map<Integer, AtomicInteger> countDupes(int[] array) {
Map<Integer, AtomicInteger> map = new HashMap<Integer, AtomicInteger>();
// first create an entry in the map for every value in the array
for (int i : array)
map.put(i, new AtomicInteger());
// now count all occurrences
for (int i : array)
map.get(i).addAndGet(1);
// now get rid of those where no duplicate exists
HashSet<Integer> discards = new HashSet<Integer>();
for (Integer i : map.keySet())
if (map.get(i).get() == 1)
discards.add(i);
for (Integer i : discards)
map.remove(i);
return map;
}
}
Use a Hashmap collection in addition to the array list where
the Hashmap key is the unique array int value and
the Hashmap value to the key is the count of each value encountered.
Walk your array list collecting these values into the hashmap adding a new item when a previous key does not exist and incrementing by 1 the values of keys that do already exist. Then iterate over the Hashmap and print out any keys where the value is > 1.
You can go through the List and put them in a Map with the count. Then it is easy figure out which one is duplicated.
For a cleaner abstraction of what you're doing, you could use the Multiset data structure from guava/google-collections. You may even find you'd rather use it than a List, depending on what you're doing with it (if you don't need the deterministic ordering of a list). You'd use it like this:
Multiset<Integer> multiset = HashMultiset.create(list);
int count = multiset.count(3); // gets the number of 3s that were in the list
In terms of what the above is doing under the covers, it's almost exactly equivalent to the suggestion of building a Map<Integer,AtomicInteger> based on your list.