If I have an ArrayList of these strings...
"String1, String1, String1, String2, String2, String2, String3, String3"
How can I find the most appearing string in this list? If there are any duplicates, I would want to put both into the same list and deal with that accordingly. How could I do this, assuming that the list of strings could be of any size.
This is about as far as I've gotten:
public String getVotedMap() {
int[] votedMaps = new int[getAvailibleMaps().size()];
ArrayList<String> mostVoted = new ArrayList<String>();
int best = 0;
for(int i = 0; i < votedMaps.length; i++) {
if(best > i) {
best = i;
} else if(best == i) {
} else {
}
}
}
getAvailibleMaps() is a list of Maps that I would choose from (again, can get any size)
Thanks!
Use HashMap
The basic Idea is loading all the values into a hashtable. Hash tables are nice because you can assign a value to a unique key. As we add all the keys to the hashtable we are checking to see if it already exists. If it does then we increment the value inside.
After we have inserted all the elements into the hashtable then we go through the hashtable one by one and find the string with the largest value. This whole process is O(n)
Map<String, Integer> map = new HashMap<String, Integer>();
for(int i = 0; i < array.length(); i++){
if(map.get(array[i]) == null){
map.put(array[i],1);
}else{
map.put(array[i], map.get(array[i]) + 1);
}
}
int largest = 0;
String stringOfLargest;
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
if( value > largest){
largest = value;
stringOfLargest = key;
}
}
if you want multiple largest strings then instead of just finding the largest and being done. You can add all the largest to a mutable list.
for example:
int largest = 0;
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
if( value > largest){
largest = value;
}
}
ArrayList<Object> arr = new ArrayList<Object>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
if( value == largest){
arr.add(key);
}
}
arr now stores all the most frequently appearing strings.
This process is still O(n)
Just iterate through the list and keep a HashMap<String,Integer> that counts how many times the string has appeared, eg.
Map<String,Integer> counts = new HashMap<String,Integer>();
for(String s : mostVoted) {
if(counts.containsKey(s)) {
counts.put(s,counts.get(s)+1);
} else {
counts.put(s,1);
}
}
// get the biggest element from the list
Map.Entry<String,Integer> e = Collections.max(counts.entrySet(),new Comparator<Map.Entry<String,Integer>>() {
#Override
public int compare(Map.Entry<String,Integer> o1, Map.Entry<String,Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
System.out.printf("%s appeared most frequently, %d times%n",e.getKey(),e.getValue());
If you can use java 8, this will give you a list of most frequent strings or throw an exception if the list is empty.
List<String> winners = strings.stream()
.collect(groupingBy(x->x, counting())) // make a map of string to count
.entrySet().stream()
.collect(groupingBy( // make it into a sorted map
Map.Entry::getValue, // of count to list of strings
TreeMap::new,
mapping(Map.Entry::getKey, toList()))
).lastEntry().getValue();
Related
I'm trying to use hashmaps to detect any duplicates in a given list, and if there is, I want to add "1" to that String to indicate its duplication. If it occurs 3 times, the third one would add "3" after that string.
I can't seem to figure that out, keeping track of the number of duplicates. It only adds 1 to the duplicates, no matter if it's the 2nd or 3rd or 4th,..etc duplicate.
This is what I have:
public static List<String> duplicates(List<String> given) {
List<String> result = new ArrayList<String>();
HashMap<String, Integer> hashmap = new HashMap<String, Integer>();
for (int i=0; i<given.size(); i++) {
String current = given.get(i);
if (hashmap.containsKey(current)) {
result.add(current+"1");
} else {
hashmap.put(current,i);
result.add(current);
}
}
return result;
}
I want to include the values that only occur once as well, as is (no concatenation).
Sample Input: ["mixer", "toaster", "mixer", "mixer", "bowl"]
Sample Output: ["mixer", "toaster", "mixer1", "mixer2", "bowl"]
public static List<String> duplicates(List<String> given) {
final Map<String, Integer> count = new HashMap<>();
return given.stream().map(s -> {
int n = count.merge(s, 1, Integer::sum) - 1;
return s + (n < 1 ? "" : n);
}).collect(toList());
}
I renamed final to output as the first one is a keyword that cannot be used as a variable name.
if (hashmap.containsKey(current)) {
output.add(current + hashmap.get(current)); // append the counter to the string
hashmap.put(current, hashmap.get(current)+1); // increment the counter for this item
} else {
hashmap.put(current,1); // set a counter of 1 for this item in the hashmap
output.add(current);
}
You always add the hard-coded string "1" instead of using the count saved in the map:
public static List<String> duplicates(List<String> given) {
List<String> result = new ArrayList<>(given.size());
Map<String, Integer> hashmap = new HashMap<>();
for (String current : given) {
if (hashmap.containsKey(current)) {
int count = hashmap.get(current) + 1;
result.add(current + count);
hashmap.put(current, count);
} else {
hashmap.put(current, 0);
result.add(current);
}
}
return result;
}
ArrayList finallist = new ArrayList<String>();
for (int i=0; i<given.size(); i++) {
String current = given.get(i);
if (hashmap.containsKey(current)) {
hashmap.put(current,hashmap.get(current)+1);
} else {
hashmap.put(current,1);
}
String num = hashmap.get(current) == 1 ? "" :Integer.toString(hashmap.get(current));
finallist.add(current+num);
}
System.out.println(finallist);
I've included a picture of the problem below that explains it in more detail. The goal is to just find the k highest occurrences in a dictionary of words. My approach is getting the frequency in a HashMap and then using a Priority Queue to store the max k elements. I then add the max k elements to my return list and return it.
For the given input in the picture, my code returns to correct output -
["i","love"]. The problem is for inputs like the one below:
input: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"]
output: ["day","sunny","is","the"]
expected: ["the","is","sunny","day"]
The correct answer would just be a reverse of my current string, however if I reverse the string before returning the original input (the one in the picture) no longer works.
I think this had something to do with how the values are being store in the priority queue when their frequency is the same...but I'm not sure of to check for that.
Any thoughts on how I could fix this?
class Solution {
public List<String> topKFrequent(String[] words, int k) {
HashMap<String, Integer> map = new HashMap<>();
List<String> mostFrequent = new ArrayList<>();
for(int i = 0; i < words.length; i++) {
if(map.containsKey(words[i])) {
map.put(words[i], map.get(words[i]) + 1);
}
else {
map.put(words[i], 1);
}
}
PriorityQueue<String> pq = new PriorityQueue<String>((a,b) -> map.get(a) - map.get(b));
for(String s : map.keySet()) {
pq.add(s);
if(pq.size() > k) {
pq.remove();
}
}
for(String s : pq) {
mostFrequent.add(s);
}
//Collections.reverse(mostFrequent);
return mostFrequent;
}
}
One way to achieve is by changing your code like below,
class Solution {
public static List<String> topKFrequent(String[] words, int k) {
HashMap<String, Integer> map = new HashMap<>();
List<String> mostFrequent = new ArrayList<>();
for(int i = 0; i < words.length; i++) {
if(map.containsKey(words[i])) {
map.put(words[i], map.get(words[i]) + 1);
}
else {
map.put(words[i], 1);
}
}
//Below I am sorting map based on asked condition and storing it into the list.
List<Map.Entry<String,Integer>> sorted = new ArrayList<>(map.entrySet());
Collections.sort(sorted,(Map.Entry<String,Integer> x,Map.Entry<String,Integer> y) -> x.getValue().compareTo(y.getValue()) == 0? x.getKey().compareTo(y.getKey()):x.getValue().compareTo(y.getValue()) > 0 ? -1 : 1 );
for(Map.Entry<String,Integer> e : sorted) {
mostFrequent.add(e.getKey());
}
return mostFrequent;
}
Here, after creating the frequency map I am sorting them based on frequency and creating one new ArrayList.
You almost did it. But you have a few bugs.
At first, your solution is not full. In original task they asked not only about frequency but additional, if frequency is equal - output elements in alphabetical order.
To achieve that you can use following comparator for PriorityQueue:
PriorityQueue<String> pq = new PriorityQueue<String>((a, b) -> {
int countComparison = Integer.compare(map.get(a), map.get(b));
if (countComparison == 0)
return b.compareTo(a);
return countComparison;
});
And, the next mistake with your solution is iterating over PriorityQueue. PriorityQueue iterator does not guarantee any particular order. From the Javadocs
The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order.
Because of it you need to poll elements from the queue. And part responsible for it:
while(!pq.isEmpty()) {
String s = pq.poll();
mostFrequent.add(s);
}
And final part - because of the order of elements in queue(from the lowest to the highest) you need to reverse output array:
Collections.reverse(mostFrequent);
The final solution will look like this:
public List<String> topKFrequent(String[] words, int k) {
HashMap<String, Integer> map = new HashMap<>();
List<String> mostFrequent = new ArrayList<>();
for(int i = 0; i < words.length; i++) {
if(map.containsKey(words[i])) {
map.put(words[i], map.get(words[i]) + 1);
}
else {
map.put(words[i], 1);
}
}
PriorityQueue<String> pq = new PriorityQueue<String>((a, b) -> {
int countComparison = Integer.compare(map.get(a), map.get(b));
if (countComparison == 0)
return b.compareTo(a);
return countComparison;
});
for(String s : map.keySet()) {
pq.add(s);
if(pq.size() > k) {
pq.remove();
}
}
while(!pq.isEmpty()) {
String s = pq.poll();
mostFrequent.add(s);
}
Collections.reverse(mostFrequent);
return mostFrequent;
}
I'm using this algorithm to compare two sets of values: a HashMap<Integer,ArrayList<Integer>> and the other ArrayList<Integer>. The goal of the program is to compare each value in the HashMap, with the values in the ArrayList, and returns a new HashMap of the similar values. So far, my program runs normally, but it returns false results.
ArrayList Example
[1.0.1.0.0]
HashMap Example
[1.0.1.1.0]
[0.1.1.0.0]
[0.1.1.1.0]
Result:
4
3
2
My Program
int k = 1;
List<Integer> listOperateur = new ArrayList<Integer>();
HashMap<Integer, Integer> sim = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, ArrayList<Integer>> e : hmm.entrySet()) {
count = 0;
for (Integer mapValue : e.getValue()) {
if (mapValue.equals(listOperateur.get(k))) {
count++;
}
}
sim.put(e.getKey(), count);
k++;
}
System.out.println("HASHMAP RESULT:");
LinkedHashMap<Integer, ArrayList<Integer>> hmm = new LinkedHashMap<>();
for (Entry<Integer, List<String>> ee : hm.entrySet()) {
Integer key = ee.getKey();
List<String> values = ee.getValue();
List<Integer> list5 = new ArrayList<>();
for (String temp : global) {
list5.add(values.contains(temp) ? 1 : 0);
}
hmm.put(key, (ArrayList<Integer>) list5);
}
//nouvelle list operateur
List<Integer> list6 = new ArrayList<Integer>();
System.out.println("liste operateur");
List<Integer> listOperateur = new ArrayList<Integer>();
listOperateur.add(1);
listOperateur.add(0);
listOperateur.add(0);
listOperateur.add(0);
Iterator iter = listOperateur.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
//calcule similarité
System.out.println("HASHMAP SIMILIRATE RESULT:");
HashMap<Integer, Integer> sim = new HashMap<Integer, Integer>();
int count;
int k = 0;
for (Map.Entry<Integer, ArrayList<Integer>> e : hmm.entrySet()) {
//if (e.getValue() != null) {
count = 0;
//you can move this part to another method to avoid deep nested code
for (Integer mapValue : e.getValue()) {
if (mapValue.equals(listOperateur.get(k))) {
count++;
}
}
sim.put(e.getKey(), count);
k++;
}
I believe you're attempting to rely on the insertion order of objects into the HashMap which is not wise, as order is not preserved. Instead, try changing hmm's type from HashMap to LinkedHashMap and see if that solves your problem.
Edit: Also, you should probably initialize k to 0 instead of 1.
I am trying to find the number of Strings that only appear exactly once in an ArrayList.
How many I achieve this (preferably with the best possible time complexity)?
Below is my method:
public static int countNonRepeats(WordStream words) {
ArrayList<String> list = new ArrayList<String>();
for (String i : words) {
list.add(i);
}
Collections.sort(list);
for (int i = 1; i < list.size(); i++) {
if (list.get(i).equals(list.get(i - 1))) {
list.remove(list.get(i));
list.remove(list.get(i - 1));
}
}
System.out.println(list);
return list.size();
}
Why doesn't it remove the String at list.get(i) and list.get(i-1)?
There is no need for sorting.
A better approach would be to use two HashSet One for maintaining repeating and one for non-repeating words. Since HashSet internally uses HashMap, Ideally contains, get, put operation has o(1) complexity. So the overall complexity of this approach would be o(n).
public static int countNonRepeats(List<String> words) {
Set<String> nonRepeating = new HashSet<String>();
Set<String> repeating = new HashSet<String>();
for (String i : words) {
if(!repeating.contains(i)) {
if(nonRepeating.contains(i)){
repeating.add(i);
nonRepeating.remove(i);
}else {
nonRepeating.add(i);
}
}
}
System.out.println(nonRepeating.size());
return nonRepeating.size();
}
Here's one simple suggestion:
First, sort your array by alphanumerical order
Iterate through with a loop, if( !list.get(i).equals(list.get(i+1)) ) → unique
If you find duplicates, increment i until you reach a different string
This will have the complexity of the sorting algorithm, since step 2+3 should be O(n)
Is there any specific need of using an ArrayList? You can do it easily by using a HashSet.
Here is the code snippet:
public static void main (String[] args) {
String[] words = {"foo","bar","foo","fo","of","bar","of","ba","of","ab"};
Set<String> set = new HashSet<>();
Set<String> common = new HashSet<>();
for (String i : words) {
if(!set.add(i)) {
common.add(i);
}
}
System.out.println(set.size() - common.size());
}
Output:
3
Here is the modified code:
public static int countNonRepeats(WordStream words) {
Set<String> set = new HashSet<>();
Set<String> common = new HashSet<>();
for (String i : words) {
if(!set.add(i)) {
common.add(i);
}
}
return (set.size() - common.size());
}
You can use hashmap to achieve this.With this approach we can count the occurrence of all the words, If we are interested in only unique words then access the element having count = 1.
HashMap<String,Integer> - key represents the String from arraylist and Integer represents the count of occurrence.
ArrayList<String> list = new ArrayList<String>();
HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
for (int i = 0; i < list.size(); i++) {
String key = list.get(i);
if (hashMap.get(key) != null) {
int value = hashMap.get(key);
value++;
hashMap.put(key, value);
} else {
hashMap.put(key, 1);
}
}
int uniqueCount = 0;
Iterator it = hashMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
if ((int) pair.getValue() == 1)
uniqueCount++;
}
System.out.println(uniqueCount);
I am having hashmap and Arraylist.
Hashmap
Map<Integer, List<String>> mMap = new HashMap<Integer, List<String>>();
Here Key (Interger) will be the index position of one element in the anotherlsit and value will be the list.
Arraylist
List<testBean> mList= new ArrayList<testBean>();
Now I want to iterate the arraylist and compare the indexposition of element in the ArrayList with the key value of Map.If it matched I will go for another logic.I got struck here on how to iterate simultaneously and compare .Please help me on this.
Why not just iterate through the list and use map get:
for(int i = 0;i < mList.size();i++) {
List<String> list = mMap.get(i);
if (list == null) {
// index was a key in map
} else {
// index was not a key in map
}
}
Strictly speaking this is not 100% correct if you have a key in map that maps to a null value. In that case you can check for key presence with mMap.containsKey() method.
for(int i = 0;i < mList.size();i++) {
if(mMap.containsKey(mList.get(i)) {
// Put your logic here
}
}
Theoretically you can do this using iterator:
Iterator<TheBean> itb = mList.iterator();
Iterator<Entry<Integer, List<String>>> itmap = mMap.iterator();
while (itb.hasNext() && itmap.hasNext()) {
TheBean b = itb.next();
Entry<Integer, List<String>> e = itmap.next();
// do you logic that I IMHO do not understand exactly.
}
However this will not work because map does not preserve order of keys. So, if I understand that index of list should match key of map you can do the following:
for (int i = 0; i < mList.size(); i++) {
TheBean b = mList.get(i);
List<String> listOfStrings = mMap.get(i);
if (listOfStrings != null) {
// implement your logic here.
}
}
I hope this helps
Try with this logic
for (Integer mapKey : mMap.keySet()) {
//iterate through list
for (String listIndex : mMap.get(mapKey)) {
//compare the map key value with list value
if(listIndex != null && mapKey == Integer.valueOf(listIndex)){
//write your logic here
}
}
}