Related
This question already has answers here:
Why cannot I increment returned value?
(5 answers)
Closed last month.
What's wrong with this? Specifically, what's wrong with intCount.put(i, intCount.get(i)++)?
public static Map<Integer, Integer> countNumbers(List<Integer> list) {
Map<Integer, Integer> intCount = new TreeMap<>();
for (Integer i : list) {
if (intCount.get(i) == null) {
intCount.put(i, 1);
} else {
intCount.put(i, ++intCount.get(i));
}
}
return intCount;
}
This works, on the other hand
public static Map<Integer, Integer> countNumbers(List<Integer> list) {
Map<Integer, Integer> intCount = new TreeMap<>();
for (Integer i : list) {
if (intCount.get(i) == null) {
intCount.put(i, 1);
} else {
intCount.put(i, intCount.get(i) + 1);
}
}
return intCount;
}
Does it mean I can't increment Integers, only int primitives? The problem is when I cast Integer into its respective primitive (or rather, an Integer returning method into its respective primitive) like this
intCount.put(i, ++(int)(intCount.get(i)));
it doesn't work either! Why?
Main.java:30: error: unexpected type
intCount.put(i, ++(int)(intCount.get(i)));
^
required: variable
found: value
1 error
intCount.get(i) gets a value, there is no variable to increment. Regardless, I would remove the if and else entirely and use Map.getOrDefault(Object, V) like
intCount.put(i, intCount.getOrDefault(i, 0) + 1);
i would like if someone can check out this piece of code, the code should transform an array into a list and then into a map. The key should have the value of the list element and the value should be True if it's an even number and False if it's odd. The array is "8, 6, 1, 5, 3, 9, 2". I'm pretty sure this is the right way but when printing the map i get a lot of lines, it's my first time doing with maps so i'm not sure if that's the way it should be or i messed something up huh. Code:
static public void toMap(int x[]) {
List<Integer> list = new ArrayList<>();
Map<Integer, String> map = new HashMap<>();
for (int t : x) {
list.add(t);
}
for(int z : list) {
String tf;
if(z % 2 == 0)
tf = "True";
else
tf = "False";
map.put(z,tf);
for (Map.Entry<Integer, String> mp : map.entrySet()) {
System.out.println(mp.getKey() + "/" + mp.getValue());
}
}
}
Getting this when printing:
Any help/tip would be appreciated, thanks in advance!
You are printing inside the for loop and that is causing the issue. You need to move it outside the for loop. Here is the updated code -
static public void toMap(int[] x) {
List<Integer> list = new ArrayList<>();
for (int t : x) {
list.add(t);
}
Map<Integer, String> map = new HashMap<>();
for(int z : list) {
String tf;
if(z % 2 == 0)
tf = "True";
else
tf = "False";
map.put(z,tf);
}
for (Map.Entry<Integer, String> mp : map.entrySet()) {
System.out.println(mp.getKey() + "/" + mp.getValue());
}
}
Also you can simplify it a bit as below -
public static void main(String[] args) {
Integer[] array = {8, 6, 1, 5, 3, 9, 2};
toMap(array);
}
static public void toMap(Integer[] x) {
List<Integer> list = Arrays.asList(x);
Map<Integer, String> map = new HashMap<>();
list.forEach(i -> {
if (i % 2 == 0)
map.put(i, "True");
else
map.put(i, "False");
});
System.out.println(map);
}
You are putting the loop for printing out the map inside the loop that creates it, so every time you add an entry it reprints the map. You actually do have the correct map -- the last few lines of output.
To fix it you should move that last for loop out to make it
for(int z : list) {
String tf;
if(z % 2 == 0)
tf = "True";
else
tf = "False";
map.put(z,tf);
}
for (Map.Entry<Integer, String> mp : map.entrySet()) {
System.out.println(mp.getKey() + "/" + mp.getValue());
}
This is a clear example of why you should always put the braces in your code, you get lost.
for(int z : list) {
String tf;
if(z % 2 == 0) {
tf = "True";
}
else {
tf = "False";
}
map.put(z,tf);
for (Map.Entry<Integer, String> mp : map.entrySet()) {
System.out.println(mp.getKey() + "/" + mp.getValue());
}
}
If we put the braces there, you can clearly see that you have the printing for-loop inside the other one. This is harder to see without the braces.
Move that printing loop outside the other one and you should be good.
You need to move the printing loop outside of the first loop.
Also, a few observations.
X == Y returns true or false depending on the value. And booleans will print out as true or false. So why not do the following:
for(int z : list) { // you can also replace list with your array here
map.put(z,z % 2 == 0);
}
// or if you want Strings
for (int z : list) {
map.put(z, z % 2 == 0 ? "True":"False");
}
To print them, you can do this.
map.forEach((k,v)->System.out.println(k + "/" + v));
You don't need to iterate twice over the array. Iterate only once, add it to list and even or odd to map.
static public void toMap(int x[]) {
// List which contains all elements of x.
List<Integer> list = new ArrayList<>();
// Map to store element as key and even or not as value
Map<Integer, Boolean> map = new HashMap<>();
for (int value: x) {
list.add(value);
map.put(value, value % 2 == 0);
}
// Printing the map
for (Map.Entry<Integer, Boolean> m : map.entrySet()) {
System.out.println(m.getKey() + "," + m.getValue());
}
}
As others have said, your problem is in the nesting. You are looping through all of your map entries for every integer in the input array. That said, I think the bigger issue is you have over-complicated your method. Using a few tricks, you can simplify your code down to something like this:
public static void toMap(int[] x) {
HashMap<Integer, String> map = new HashMap<>();
ArrayList<Integer> list = new ArrayList<>();
for (int i : x) {
map.put(i, (i & 1) == 0 ? "True" : "False"); //puts "True" if i is even, else "False"
}
list.addAll(map.keySet()); //adds all the map's keys to the ArrayList
map.forEach((k, v) -> System.out.printf("%d/%s%n", k, v)); //prints out all the entries formatted as you specified
}
Or, if you don't actually need the ArrayList for anything specific, you can just get rid of it:
public static void toMap(int[] x) {
HashMap<Integer, String> map = new HashMap<>();
for (int i : x) {
map.put(i, (i & 1) == 0 ? "True" : "False"); //puts "True" if i is even, else "False"
}
map.forEach((k, v) -> System.out.printf("%d/%s%n", k, v)); //prints out all the entries formatted as you specified
}
Or, if you don't actually need any of the functions of the map, you can just get rid of that, too. Just print straight from the for loop, like so:
public static void toMap(int[] x) {
for (int i : x) {
System.out.printf("%d/%s%n", i, (i & 1) == 0 ? "True" : "False");
}
}
Or, if you don't mind the true/false being all lowercase, you can let Java do the string conversion for you:
public static void toMap(int[] x) {
for (int i : x) {
System.out.printf("%d/%s%n", i, (i & 1) == 0);
}
}
Finally, if you're into one-liners, and don't mind it being a bit messy, you can do it all in one line:
public static void toMap(int[] x) {
IntStream.of(x).forEach((i) -> System.out.printf("%d/%s%n", i, (i & 1) == 0));
}
Problem
Data is in the format:
Map<String, Map<String, Integer>>
Which looks something like this:
{"MilkyWay": {"FirstStar" : 3, "SecondStar" : 9 .... }, "Andromeda": {"FirstStar" : 10, "SecondStar" : 9 .... } }
I want to compare the Star values in a quick loop, so I'd like to compare the integer value of FirstStar in MilkyWay and Andromeda and have it return true or falseif the values are the same or not. Since this Map of Maps is huge.
My Attempt
I'd like to do it something like:
//GalaxyMap<String, <Map<String, Integer>>
for (Map<String, Integer> _starMap : GalaxyMap.values())
{
for (String _starKey : _starMap.keySet()){
//Can't quite think of the correct logic... and I'm tired...
}
}
I'd like to keep it as short as possible... I've been staring at this for a while and I'm going in circles with it.
EDIT
Outer keys differ, Inner keys are the same
Also since this is a response from a server, I don't know the size it's going to be
Why does this need to be a map. If you're always using "FirstStar", "SecondStar" etc, as your keys, then why not make it a list instead..
Map<String, List<Integer>>
Then you can do something like:
public boolean compareGalaxyStar(String galaxyName, String otherGalaxyName, int star) {
List<Integer> galaxyStars = galaxyMap.get(galaxyName);
List<Integer> otherGalaxyStars = galaxyMap.get(otherGalaxyName);
return galaxyStars.get(star) == otherGalaxyStars.get(star);
}
NOTE: You need to do some validation to make sure the input is correct.
To implement this for all stars, it is not much different.
if(galaxyStars.size() == otherGalaxyStars.size()) {
for(int x = 0; x < galaxyStars.size(); x++) {
// Perform your comparisons.
if(galaxyStars.get(x) != otherGalaxyStars.get(x)) {
// Uh oh, unequal.
return false;
}
}
}
If the structure of the inner maps also could differ, you should do something like that:
static boolean allStarValuesEqual(Map<String, Map<String, Integer>> galaxies) {
Map<String, Integer> refStars = null;
for (Map<String, Integer> galaxy : galaxies.values()) {
if (refStars == null) {
refStars = galaxy;
} else {
for (Entry<String, Integer> currentStar : galaxy.entrySet()) {
if (!currentStar.getValue().equals(refStars.get(currentStar.getKey()))) {
return false;
}
}
}
}
return true;
}
Please check below program along with output:
package com.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class CompareMapValues {
private final static String FS = "FirstStar";
private final static String SS = "SecondStar";
private final static String MW = "MilkyWay";
private final static String A = "Andromeda";
public static void main(String[] args) {
Map> map = new HashMap>();
Map innerMap1 = new HashMap();
innerMap1.put(FS, 3);
innerMap1.put(SS, 9);
Map innerMap2 = new HashMap();
innerMap2.put(FS, 10);
innerMap2.put(SS, 9);
map.put(MW, innerMap1);
map.put(A, innerMap2);
Set set = map.keySet();
for(String s: set) {
Map outerMap = map.get(s);
Set set2 = map.keySet();
for(String s2: set2) {
Map innerMap = map.get(s2);
if(!s2.equals(s)) {
Set set3 = outerMap.keySet();
for(String s3: set3) {
int i1 = outerMap.get(s3);
Set set4 = innerMap.keySet();
for(String s4: set4) {
int i2 = innerMap.get(s3);
if(s3.equals(s4) && i1==i2) {
System.out.println("For parent " + s + " for " + s3 + " value is " + i1);
}
}
}
}
}
}
}
}
//Output:
//For parent Andromeda for SecondStar value is 9
//For parent MilkyWay for SecondStar value is 9
Hope this helps.
Map<String,String> votes = new HashMap<String,String>
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
How can I retrieve the value that most a occur in the HashMap above, in this case that would be "School". I would appreciate the most efficient and clear method to approach.
A simpler solution is to just look at the values.
public static <E> E mostFrequentElement(Iterable<E> iterable) {
Map<E, Integer> freqMap = new HashMap<>();
E mostFreq = null;
int mostFreqCount = -1;
for (E e : iterable) {
Integer count = freqMap.get(e);
freqMap.put(e, count = (count == null ? 1 : count+1));
// maintain the most frequent in a single pass.
if (count > mostFreqCount) {
mostFreq = e;
mostFreqCount = count;
}
}
return mostFreq;
}
and for a Map you can do
V v = mostFrequentElement(map.values());
One solution would be:
Construct a new HashMap that has a String key and an int value.
For each value of your current HashMap:
Add the value as the key in the new HashMap and the value as 1 if it's the first time you're inserting it.
Otherwise, increment the value by one for the current key.
Now iterate on the newly created map and retrieve the key that has the maximum value.
For your current map:
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
You'll first insert School as a key, with value 1. Then you face School again, so you increment the value by 1, having a count of 2. Now you insert Work with value 1, and Party with value 1 as well.
After iterating on the map, you'll get School with the highest value. And that's what you want!
Just using the API :
Map<String,String> votes = new HashMap<String,String>();
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
Collection<String> c = votes.values();
List<String> l = new ArrayList<>(c);
Set<String> set = new HashSet<>(c);
Iterator<String> i = set.iterator();
String valueMax = "";
int max = 0;
while(i.hasNext()){
String s = i.next();
int frequence = Collections.frequency(l, s);
if(frequence > max){
max = frequence;
valueMax = s;
}
}
System.out.println(valueMax+": "+max);
Output :
School: 2
Here is the implementation of Maroun pseudocode. Try,
Map<String, String> votes = new HashMap<String, String>();
votes.put("Henk", "School");
votes.put("Elise", "School");
votes.put("Jan", "Work");
votes.put("Mert", "Party");
//Define a countMap with String as value, Integer for count
Map<String, Integer> countMap = new HashMap<>();
for (Map.Entry<String, String> entry : votes.entrySet()) {
if (countMap.containsKey(entry.getValue())) {
countMap.put(entry.getValue(), countMap.get(entry.getValue()) + 1);
} else {
countMap.put(entry.getValue(), 1);
}
}
// Got the number of maximum occuarance
Integer maxNum = Collections.max(countMap.values());
String result = "";
// Iterate to search the result.
for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
if(maxNum==entry.getValue()){
result=entry.getKey();
}
}
System.out.println(result);
I believe this will do what you want -
/**
* Get the most frequent value present in a map.
*
* #param map
* The map to search.
* #return The most frequent value in the map (or null).
*/
public static <K, V> V getMostFrequentValue(
Map<K, V> map) {
// Make sure we have an entry.
if (map != null && map.size() > 0) {
// the entryset from our input.
Set<Entry<K, V>> entries = map.entrySet();
// we need a map to hold the count.
Map<V, Integer> countMap = new HashMap<V, Integer>();
// iterate the entries.
for (Entry<K, V> entry : entries) {
// get the value.
V value = entry.getValue();
if (countMap.containsKey(value)) {
// if we've seen it before increment the previous
// value.
countMap.put(value, countMap.get(value) + 1);
} else {
// otherwise, store 1.
countMap.put(value, 1);
}
}
// A holder for the maximum.
V maxV = null;
for (Entry<V, Integer> count : countMap.entrySet()) {
if (maxV == null) {
maxV = count.getKey();
continue;
}
if (count.getValue() > countMap.get(maxV)) {
maxV = count.getKey();
}
}
return maxV;
}
return null;
}
You could override the put() and remove() of the HashMap class and create your custom one that also controls for the number of objects added. Like so:
public class MyHashMap<K, V> extends HashMap<K, V> {
private HashMap<String, Integer> countMap = new HashMap<String, Integer>();
#Override
public V put(K key, V value) {
Integer count = countMap.get(value);
if (count != null) {
countMap.put((String) value, ++count);
} else {
countMap.put((String) value, new Integer(1));
}
return super.put(key, value);
}
#Override
public V remove(Object key) {
String countKey = (String) get(key);
Integer count = countMap.get(countKey);
if (count != null) {
countMap.put(countKey, --count);
}
return super.remove(key);
}
public Integer getCount(Object value) {
return countMap.get((String)value);
}
}
This way you don't have to loop over the elements of your HashMap to count them. Instead, after you add them:
Map<String,String> votes = new MyHashMap<String,String>
votes.put("Henk","School");
votes.put("Elise","School");
votes.put("Jan","Work");
votes.put("Mert","Party");
You could just get the count for each as:
Integer schoolCount = votes.getCount("School");
Thanks for the help from Zirak In my previous post i implemented the following in JavaScript:
var arr1 =[0,1,2,3];
var arr2 =["ac", "bc", "ad", "e"];
var result = arr1 .sort(function(i, j){return arr2[i].localeCompare(arr2[j])})
document.write(result );
The way to achieve this is quite compact in JavaScript, can a java implementation of this be also achieved by such simplicity? I could only think of implementing the Comparable interface like the following:
public class testCompare {
public static String[] arr2={"ac", "bc", "ad", "e"};
public static Obj[] arr1={new Obj(0), new Obj(1), new Obj(2), new Obj(3)};
static class Obj implements Comparable{
int index=0;
public Obj(int i){
index=i;
}
#Override
public int compareTo(Object o) {
return arr2[index].compareTo(arr2[((Obj)o).index]);
}
}
}
but if the array have X many items, then I will have to create X many Objs, is there another way that I could achieve this more simply? Another question is, if I do the above method what would be the time complexity for the sorting both in java and in JavaScript, are they all O(n^2)? Thanks a lot
public class MyComparator implements Comparator<Integer> {
#Override
public int compare(Integer i1, Integer i2) {
return arr2[i1.intValue()].compareTo(arr2[i2.intValue()]);
}
}
Arrays.sort(arr1, new MyComparator());
This is the equivalent of the JavaScript sort. The Comparator object is used as the callback function is used in JavaScript.
Try using a TreeMap<String, Integer> (assuming you want to sort integers) which means all entries are sorted by their string key:
SortedMap<String, Integer> map = new TreeMap<String, Integer>();
map.put("ac", 0);
map.put("bc", 1);
map.put("ad", 2);
map.put("e", 3);
for( Map.Entry<String, Integer> entry : map.entrySet() )
{
System.out.println(entry.getKey() + " - " + entry.getValue());
}
Output:
ac - 0
ad - 2
bc - 1
e - 3
To sort an array and get the new order of the previous indices you could iterate over the array and add the indices as Integer objects to the map:
String[] input = {"ab", "bc", "ad" , "e" };
SortedMap<String, Integer> map = new TreeMap<String, Integer>();
for( int i = 0; i < input.length; ++i )
{
map.put(input[i], i); //or use values from another array, e.g. map.put(inputKeys[i], inputValues[i]);
}
If you need to sort the keys by anything else but the natural order, you can add a Comparator<String> to the TreeMap constructor.
public class SortA1byA2array
{
public static void main (String[] args)
{
int[] arr1={2,1,2,5,7,1,9,8,3,6,8,8};
int[] arr2={2,1,8,3};
TreeMap hm=new TreeMap();
int count=1;
for(int i=0;i<arr1.length;i++){
if(hm.containsKey(arr1[i])){
hm.put(arr1[i], ++count);
}
else{
count=1;
hm.put(arr1[i],count);
}
}
for(int i=0;i<arr2.length;i++){
if(hm.containsKey(arr2[i])){
for(int j=0;j<(Integer)hm.get(arr2[i]);j++){
System.out.println(arr2[i]);
}
hm.remove(arr2[i]);
}
}
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey());
it.remove();
}
}
}
In response to the second part of you question: Arrays.sort in Java has guaranteed O(n log n) time complexity, as specified in the API.