I was given a problem - there is a box containing label and has value in it. for example - box with label 'a' contains value 2, box with label 'b' contains value 7 etc. I was asked to find the pairs that adds to sum 10. I wrote below code to find the pair using hashmap. But it contains same result twice with only difference of position of letter.
For example - (a,e) is same as (e,a)
How can I keep/print only the unique pair?
Below is my code :
public class BoxValue {
public void pair()
{
int sum = 10;
HashMap<Integer, Character> m = new HashMap<Integer, Character>();
m.put(2, 'a');
m.put(7, 'b');
m.put(4, 'c');
m.put(3, 'd');
m.put(8, 'e');
m.put(6, 'f');
Set<Integer> s = m.keySet();
for(Integer in : s)
{
if(m.containsKey(sum-in))
System.out.println(m.get(in)+","+m.get(sum-in));
}
}
public static void main(String[] args) {
BoxValue bv = new BoxValue();
bv.pair();
}
}
I would just use a Set to keep track of which complements you've already seen:
Set<Integer> seen = new HashSet<>();
for (Integer in : m.keySet())
{
if(m.containsKey(sum-in) && !seen.contains(in))
{
System.out.println(m.get(in) + "," + m.get(sum-in));
seen.add(sum-in);
}
}
You can do it without any additional storage if you're able to modify the map, at the loss of some clarity:
for (Integer in : m.keySet())
{
if(m.containsKey(sum-in) && m.get(in) != null)
{
System.out.println(m.get(in) + "," + m.get(sum-in));
m.put(sum-in, null);
}
}
Output:
a,e
d,b
c,f
You can use a map for keys
List<Integer> s = new ArrayList<>(m.keySet()); // Create a key list
HashMap<Integer, Boolean> pos = new HashMap<Integer, Boolean>(); // Map for used key
for (int i = 0; i < s.size(); i++) {
if (m.containsKey(sum - s.get(i)) && !pos.containsKey(sum - s.get(i)))
System.out.println(m.get(s.get(i)) + "," + m.get(sum - s.get(i)));
pos.put(s.get(i), true); // Update map
}
I wrote a program in Java where it retrieves records from a database table and stored them in a hashmap.
The keys and values of them are like the following:
Key(represent words) Values(represent filename)
w1 file1
w2 file1
w3 file2
w4 file1
w5 file2
w6 file1,file2
............
The list goes on and on but this is just an idea of how it looks like.As you can see, there's no duplicate for words and they are unique.
Given that I have this hashmap info,I need to find the intersection of the key and it's next key and return the results of the intersection. The idea looks like this:
w1∩w2= file1
w2∩w3= empty
w3∩w4= empty
........and it keeps going until it reaches the finishes the final pair of keys in the hashmap.
Since the pair of intersection results depends on the number of keys in the hashmap,I am guessing I'll need to use some loop to keep it iterating to return all the results.
Is there a way on how to get the intersection of each subsequent keys and also a way that is optimize regardless the size of the hashmap?
I appreciate any suggestion.
Make a variable that will hold all those intersections. In your loop retrieve 2 keys at a time. Compare each values of the 2 keys and if they are the same add the value to your intersection holder. Repeat the steps until there is no more pairs.
Here is the code.
Add this below your try/catch
LinkedHashmap<String, Set<String>> intersectionMap = new LinkedHashmap<>();
if (map.keySet() != null) {
String[] keys = map.keySet().toArray(new String[map.keySet().size()]);
for (int i = 0; i < keys.length - 1; i++) {
String key1 = keys[i];
String key2 = keys[i + 1];
TreeSet<String> interSection = intersection(map.get(key1), map.get(key2));
intersectionMap.put(key1 + "∩" + key2, interSection);
}
}
Add this helper method. This method will find the intersection of the two sets. This will be the key in solving your problem.
public static TreeSet<String> intersection(TreeSet<String> setA, TreeSet<String> setB) {
// An optimization to iterate over the smaller set
if (setA.size() > setB.size()) {
return intersection(setB, setA);
}
TreeSet<String> results = new TreeSet<>();
for (String element : setA) {
if (setB.contains(element)) {
results.add(element);
}
}
return results;
}
Yet another version with set operations:
Map<String>, Set<String>> intersections(Map<String, TreeSet<String>> map) {
Map<String>, Set<String>> result = new TreeMap<>();
List<String> words = new ArrayList<>(map.keySet());
words.sort();
for (int i = 0; i < words.size() - 1; ++i) {
String wordI = words.get(i);
Set<String> valueI = map.get(wordI);
for (int j = i + 1, j < words.size(); ++j) {
String wordJ = words.get(j);
Set<String> valueJ = map.get(wordJ);
String word = wordi + "∩" + words[j];
Set<String> value = new TreeSet<>(valueI);
value.retainAll(valueJ);
result.put(word, value);
}
}
return result;
}
My code iterates over a char array (char[] charArray), and finds for the key. The key is then used to find the value in a Map. However, the map.get() function is giving me a null even thought I set it as a value and i am not sure why. Thanks!
parameters for this method are:
LinkedBinaryTree<String> and HashMap<String, Integer>
for (int i = 0; i < charArray.length; i++) {
if (Character.isLetter(charArray[i])) {
// Why is map.get(charArray[i]) null??
String char2String = Character.toString(charArray[i]);
if (map.get(char2String) == null) {
throw new IllegalArgumentException("int is null");
}
int k = map.get(char2String);
charArray[i] = Integer.toString(k).charAt(0);
}
}
This is a testcase i wrote to test the method.
#Test
public void testSubstituteMap() {
LinkedBinaryTree<String> tree2 = Assignment.prefix2tree("- x + 1 + x x");
HashMap<String, Integer> Map = new HashMap<String, Integer>();
Map.put("x", 5);
tree2 = Assignment.substitute(tree2, Map);
LinkedBinaryTree<String> expected = Assignment.prefix2tree("- 5 + 1 + 5 5");
assertEquals(Assignment.tree2prefix(expected), Assignment.tree2prefix(tree2));
}
Which results in:
You are putting String keys and trying to get the same with a char key.
Note that in Java "x" is not equals to 'x'
You can either change your Map to char keys or use String array. Since they are single letters, I suggest to keep them with Char's.
I would like to ask if I'm able to add dynamic hashmap keys in java?
For Example
...
String name = reader.next();
HashMap<String, Integer> map = new HashMap<>();
map.put(name, 1);
Using this method, how can I add multiple data without doing this:
...
...
map.put("JACK", 1);
map.put("JOHN", 2);
map.put("JACKER", 3);
And also, how can I loop through my hashmap to print out all the keys in hashmap?
To add multiple elements use a loop, like a for loop.
Scanner sc = new Scanner(System.in);
HashMap<String, Integer> map = new HashMap();
int i = 1;
while(sc.hasNext()){
String s = sc.nextLine();
map.put(s, i++);
}
printMap(map);
To print a HashMap we use iterator.
public static void printMap(Map mp) {
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
}
}
Is there a way to find the most common String in an ArrayList?
ArrayList<String> list = new ArrayList<>();
list.add("test");
list.add("test");
list.add("hello");
list.add("test");
Should find the word "test" from this list ["test","test","hello","test"]
Don't reinvent the wheel and use the frequency method of the Collections class:
public static int frequency(Collection<?> c, Object o)
Returns the number of elements in the specified collection equal to
the specified object. More formally, returns the number of elements e
in the collection such that (o == null ? e == null : o.equals(e)).
If you need to count the occurrences for all elements, use a Map and loop cleverly :)
Or put your list in a Set and loop on each element of the set with the frequency method above. HTH
EDIT / Java 8: If you fancy a more functional, Java 8 one-liner solution with lambdas, try:
Map<String, Long> occurrences =
list.stream().collect(Collectors.groupingBy(w -> w, Collectors.counting()));
In statistics, this is called the "mode". A vanilla Java 8 solution looks like this:
Stream.of("test","test","hello","test")
.collect(Collectors.groupingBy(s -> s, Collectors.counting()))
.entrySet()
.stream()
.max(Comparator.comparing(Entry::getValue))
.ifPresent(System.out::println);
Which yields:
test=3
jOOλ is a library that supports mode() on streams. The following program:
System.out.println(
Seq.of("test","test","hello","test")
.mode()
);
Yields:
Optional[test]
(disclaimer: I work for the company behind jOOλ)
As per question, Specifically just to get word, not the number of times (i.e. value of key).
String mostRepeatedWord
= list.stream()
.collect(Collectors.groupingBy(w -> w, Collectors.counting()))
.entrySet()
.stream()
.max(Comparator.comparing(Entry::getValue))
.get()
.getKey();
You can make a HashMap<String,Integer>. If the String already appears in the map, increment its key by one, otherwise, add it to the map.
For example:
put("someValue", 1);
Then, assume it's "someValue" again, you can do:
put("someValue", get("someValue") + 1);
Since the key of "someValue" is 1, now when you put it, the key will be 2.
After that you can easily go through the map and extract the key that has the highest value.
I didn't write a full solution, try to construct one, if you have problems post it in another question. Best practice is to learn by yourself.
I think the best way to do it is using maps containing counts.
Map<String, Integer> stringsCount = new HashMap<>();
And iterate over your array filling this map:
for(String s: list)
{
Integer c = stringsCount.get(s);
if(c == null) c = new Integer(0);
c++;
stringsCount.put(s,c);
}
Finally, you can get the most repeated element iterating over the map:
Map.Entry<String,Integer> mostRepeated = null;
for(Map.Entry<String, Integer> e: stringsCount.entrySet())
{
if(mostRepeated == null || mostRepeated.getValue()<e.getValue())
mostRepeated = e;
}
And show the most common string:
if(mostRepeated != null)
System.out.println("Most common string: " + mostRepeated.getKey());
You could use a HashMap<String,Integer>. Looping through the array, you can check for each String if it is not already a Key of your HashMap, add it and set the value to 1, if it is, increase its value by 1.
Then you have a HashMap with all unique Strings and an associated number stating their amount in the array.
If somebody need to find most popular from usual String[] array (using Lists):
public String findPopular (String[] array) {
List<String> list = Arrays.asList(array);
Map<String, Integer> stringsCount = new HashMap<String, Integer>();
for(String string: list)
{
if (string.length() > 0) {
string = string.toLowerCase();
Integer count = stringsCount.get(string);
if(count == null) count = new Integer(0);
count++;
stringsCount.put(string,count);
}
}
Map.Entry<String,Integer> mostRepeated = null;
for(Map.Entry<String, Integer> e: stringsCount.entrySet())
{
if(mostRepeated == null || mostRepeated.getValue()<e.getValue())
mostRepeated = e;
}
try {
return mostRepeated.getKey();
} catch (NullPointerException e) {
System.out.println("Cannot find most popular value at the List. Maybe all strings are empty");
return "";
}
}
case non-sensitive
i know this takes more time to implement but you can use heap data structure by storing in the nodes the count and the string information
You can use Guava's Multiset:
ArrayList<String> names = ...
// count names
HashMultiset<String> namesCounts = HashMultiset.create(names);
Set<Multiset.Entry<String>> namesAndCounts = namesCounts.entrySet();
// find one most common
Multiset.Entry<String> maxNameByCount = Collections.max(namesAndCounts, Comparator.comparing(Multiset.Entry::getCount));
// pick all with the same number of occurrences
List<String> mostCommonNames = new ArrayList<>();
for (Multiset.Entry<String> nameAndCount : namesAndCounts) {
if (nameAndCount.getCount() == maxNameByCount.getCount()) {
mostCommonNames.add(nameAndCount.getElement());
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class StringChecker {
public static void main(String[] args) {
ArrayList<String> string;
string = new ArrayList<>(Arrays.asList("Mah", "Bob", "mah", "bat", "MAh", "BOb"));
Map<String, Integer> wordMap = new HashMap<String, Integer>();
for (String st : string) {
String input = st.toUpperCase();
if (wordMap.get(input) != null) {
Integer count = wordMap.get(input) + 1;
wordMap.put(input, count);
} else {
wordMap.put(input, 1);
}
}
System.out.println(wordMap);
Object maxEntry = Collections.max(wordMap.entrySet(), Map.Entry.comparingByValue()).getKey();
System.out.println("maxEntry = " + maxEntry);
}
With this method, if there is more than one most common elements in your ArrayList, you get back all of them by adding them to a new ArrayList.
public static void main(String[] args) {
List <String> words = new ArrayList<>() ;
words.add("cat") ;
words.add("dog") ;
words.add("egg") ;
words.add("chair") ;
words.add("chair") ;
words.add("chair") ;
words.add("dog") ;
words.add("dog") ;
Map<String,Integer> count = new HashMap<>() ;
for (String word : words) { /* Counts the quantity of each
element */
if (! count.containsKey(word)) {
count.put(word, 1 ) ;
}
else {
int value = count.get(word) ;
value++ ;
count.put(word, value) ;
}
}
List <String> mostCommons = new ArrayList<>() ; /* Max elements */
for ( Map.Entry<String,Integer> e : count.entrySet() ) {
if (e.getValue() == Collections.max(count.values() )){
/* The max value of count */
mostCommons.add(e.getKey()) ;
}
}
System.out.println(mostCommons);
}
}
There are a lot of answers suggesting HashMaps. I really don't like them, because you have to iterate through them once again anyway. Rather, I would sort the List
Collections.sort(list);
and then loop through it. Something similar to
String prev = null, mostCommon=null;
int num = 0, max = 0;
for (String str:list) {
if (str.equals(prev)) {
num++;
} else {
if (num>max) {
max = num;
mostCommon = str;
}
num = 1;
prev = str;
}
}
should do it.