It puts wrong null value from String array in HashMap - java

i am a newbie in Java (coming from JavaScript developing on Adobe LiveCycle) and facing the following problem:
I have a String array with several items. I want to put only the items with the value "a" to a HashMap. But instead of 3 "a" values in the HashMap i get 1 null value there. Why is that?
String[] s = {"a", "a", "b", "a"};
Map m = new HashMap();
for (int i = 0; i < s.length; i++) {
if (s[i].equals("a")) {
m.put(i, s[i]);
}
}
for (int i = 0; i < m.size(); i++) {
System.out.println(m.get(i));
}
// Prints
//a
//a
//null

You are putting the items in the map with key 0, 1 and 3.
You are taking them out with key 0, 1, an 2.
Use:
for (Object o : m.keySet()) {
System.out.println(m.get(o));
}
or - better:
Map<Integer, String> m = new HashMap<>();
...
for (Integer i : m.keySet()) {
System.out.println(i + " -> " + m.get(i));
}

You put the items with their corresponding index in array s in the Map, i.e. you have a Map with content {0=a, 1=a, 3=a}. Therefore if you try to access the map with key 2 (m.get(2)), you get a null since key 2 is not found in m.
Instead of using a for-loop over m's size, I recommend iteration over m's keySet() via a foreach-loop:
for (Object key : m.keySet()) {
System.out.println("key: " + key + ", value: " + m.get(key));
}
On a sidenote: you are using raw types. You should bind the types of the Map and HashMap properly (see the Javadoc of Map for details): Map<Integer, String> m = new HashMap<Integer, String>();. With properly bound types, key in the for-loop can be of type int or Integer. I recommend type Integer to avoid unnecessary Auto(un)boxing.

Your code is working correctly, but you are accessing it not correctly.
String[] s = {"a", "a", "b", "a"};
for (int i = 0; i < s.length; i++) {
if (s[i].equals("a")) {
m.put(i, s[i]);
}
}
This puts it like this
First iteration : m.put(0, "a");
Second iteration : m.put(1, "a");
Third iteration : "b" doest not equal "a" but still counts the index i up
Fourth iteration: m.put(3, "a");
Apart from the other answers you can still use your range based loop and access it with an Iterator
Iterator<String> it = m.values().iterator();
while (it.hasNext()) {
System.out.println(it.next());
}

Related

How can I increment the Key of a TreeMap when I want to insert the same key?

I have a TreeMap where there is a list of id (the Key) and more data that would be the values. So, when I insert a key and value to the TreeMap, it goes well when the key isnĀ“t in the TreeMap. The problem is when it's in there. I have to update al the Key from the new one, so the new Key will be in his position, and the one that was before in that position will be in the next one.
Example:
Key: 1 Value: a
Key: 2 Value: b
Key: 3 Value: c
Key: 4 Value: d
Key: 5 Value: e
Insert Key 3, value f:
Key: 1 Value: a
Key: 2 Value: b
Key: 3 Value: f
Key: 4 Value: c
Key: 5 Value: d
Key: 6 Value: e
The Map behaves exactly as it should: Every key in a Map is unique. Means: No duplicate keys. If you put an entry with a key that already exists, it will override the old entry.
If you just want an incrementing list of items, use a List:
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
print it:
for(int i=0; i<list.size(); i++) {
System.out.println("Key: " + (i+1) + " Value: " + list.get(i));
}
When you now want to insert something in the middle, just use add with index:
list.add(2, "f");
result of print:
Key: 1 Value: a
Key: 2 Value: b
Key: 3 Value: f
Key: 4 Value: c
Key: 5 Value: d
Key: 6 Value: e
You haven't specified how the map is to be used nor whether your keys are more complex and random than specified. So I offer a different possibility.
first, create some data.
int[] keys = { 1,5,7, 10,12,15,40,40,50,18,10,8,
10, 3, 4, 5, 10, 12, 14, 19 };
String[] values = "abcdefghijklmnopqrstuvwxyz".split("");
start off with a TreeMap<Integer, List<String>>
Then store them as follows:
NavigableMap<Integer, List<String>> map = new TreeMap<>();
for(int i = 0; i < keys.length; i++) {
map.computeIfAbsent(keys[i], v-> new ArrayList<>()).add(values[i]);
}
map.entrySet().forEach(System.out::println);
Prints (each element is in a list associated with its original ID)
1=[a]
3=[n]
4=[o]
5=[b, p]
7=[c]
8=[l]
10=[d, k, m, q]
12=[e, r]
14=[s]
15=[f]
18=[j]
19=[t]
40=[g, h]
50=[i]
Now create another map to provide a one to one mapping of key to element.
int start = map.firstKey();
for(int key : map.keySet()) {
start = key < start ? start : key;
for (String v : map.get(key)) {
map2.put(start++, v);
}
}
System.out.println(map2);
Prints
{1=a, 3=n, 4=o, 5=b, 6=p, 7=c, 8=l, 10=d, 11=k, 12=m, 13=q, 14=e,
15=r, 16=s, 17=f, 18=j, 19=t, 40=g, 41=h, 50=i}
The point being if your ids are not sequential starting at 0, you can't use a list as lists can't have gaps between the indices. Otherwise a list is fine.
Using for loop for of adding same items from a list.
If the Map has already added that keys(Strings), you replace the old value(Integer) with getting it and incrementing it by 1
> List<String> list = new ArrayList<>(List.of("A", "B", "B", "C", "D",
> "E", "E", "E", "F", "G", "H"));
> Map<String, Integer> letters = new HashMap<>();
> for (String s : list) {
> if (letters.containsKey(s)) {
> letters.put(s, letters.get(s) + 1);
> } else {
> letters.put(s, 1);
> }
For the simple use case as given in your example you could try something like below, assuming your keys are sequential :
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(4, "d");
map.put(5, "e");
System.out.println("Before inserting new key value pair:");
System.out.println(map);
int newKey = 3;
String newValue = "f";
if (map.containsKey(newKey)) {
map.keySet().stream()
.filter(e -> e >= newKey)
.collect(Collectors.toCollection(ArrayDeque::new))
.descendingIterator()
.forEachRemaining(e -> {
map.put(e + 1, map.get(e));
});
}
map.put(newKey, newValue);
System.out.println("\nAfter inserting new key value pair:");
System.out.println(map);
}

Hashmap Key with multiple values without duplication

I have a Map with key as String and value as List as below
<Key>Path1 Value=[164,123,111,131]
<Key>Path2 Value=[164,122,135,133]
<Key>Path3 Value=[190,144,100,126]
<Key>Path4 Value=[113,122,453,117]
I want to compare each Key's Value with other Key's Value like Path1 Value with rest of Path's values and so on,
and also no duplicate comparision should happen, like if Path1 value is compared in 1st iteration . It should not compare Path2 with Path1 in 2nd iteration.
Am stuck with this problem . Please help me with any solution. Thanks in advance .
I have started with following code :
for (Map.Entry<String, List<String>> entry : map1.entrySet()) {
String key = entry.getKey();
for (String val : entry.getValue()) {
// do something with key and each val
}
}
Only compare keys where the first is less than the second, or some similar simple strategy.
for (String key1 : map.keySet()) {
for (String key2 : map.keySet()) {
if (key1.compareTo(key2) < 0) {
// compare key1 to key2
}
}
}
Maybe, this would be a better strategy than one suggested by Peter Lawrey cause it's not O(N*N)
Map<String, List<String>> map = new HashMap<>();
map.put("Path1", new ArrayList<>(Arrays.asList("164","123","111","131")));
map.put("Path2", new ArrayList<>(Arrays.asList("164","122","135","133")));
map.put("Path3", new ArrayList<>(Arrays.asList("190","144","100","126")));
map.put("Path4", new ArrayList<>(Arrays.asList("113","122","453","117")));
List<String> list = new LinkedList<>(map.keySet());
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
List<String> temp = new ArrayList<>(map.get(list.get(i)));
if (temp.removeAll(map.get(list.get(j)))) {
// do what you want
System.out.println(list.get(i) + " has duplicates with " + list.get(j));
}
}
}

How to string parse into hashmap using java language

I have a string but cannot parse it into Map
string s="sakib hasan : 3 : sumon ali : 4 : tutul : 100
I need to create a HashMap from above string. sakib hasan,sumon ali,tutul,shila akter should be KEY of HashMap and 3,4,100,1, should be VALUEs of KEYs.
I have tried with the flowing code but unable to solve the problem
Map<String, Integer>amap=new HashMap<String,Integer>();
String[] splt=s.split(":");
for (String string : splt)
{
String[] pair=string.split(" ");
amap.put(pair[0])+Integer.parseInt(pair[1]);
}
Is there a way can I do this without hard coding
Try this.
Your split on ":" will return each item individually.
Then you just have to take each group as a set of two which you can account for in the for loop with i+=2
Map < String, Integer > amap = new HashMap < String, Integer > ();
String[] splt = s.split(" : ");
for (int i = 0; i < splt.length; i += 2) {
amap.put(splt[i],Integer.parseInt(splt[i + 1]));
}
In your code, your for loop is going through each element that you split and every single time, adding the hashmap only index 0 & 1. You need to increment the indices.
String s = "sakib hasan : 3 : sumon ali : 4 : tutul : 100 : shila akter : 1";
Map<String, Integer> amap = new HashMap<String, Integer>();
String[] splt = s.split(":");
for(int i = 1; i < splt.length;i+=2)
amap.put(splt[i-1].trim(), Integer.parseInt(splt[i].trim()));
Here is a similar solution using streams instead of a for loop:
IntStream.range(0, splt.length / 2)
.forEach(i -> map.put(splt[i], Integer.parseInt(splt[i + 1]));
Or you could turn the .forEach into a collector that creates the map.
At least,I got the answer
Map<String, Integer>amap=new HashMap<String,Integer>();
String[] splt=s.split(":");
try {
for (int i = 0; i <= pair.length; i +=2) {
amap.put(pair[i].trim(), Integer.parseInt(pair[(1 + i)].trim()));
}
} catch (Exception e) {
}

Map elements in a list to positions in another list

Imagine we have two lists and want to know the postions of elements from one list in the other. To illustrate:
List<String> one = Arrays.asList("B", "I", "G");
List<String> another = Arrays.asList("L", "A", "R", "G", "E");
Result would be:
[-1, -1, 3]
because neither B nor I occur in second list, but G does on 3rd position.
This is what I came with so far:
<E> List<Integer> indices(List<E> elements, List<E> container) {
List<Integer> indices = new ArrayList<>(elements.size());
for (int i = 0; i < elements.size(); i++) {
indices.add(container.indexOf(indices.get(i)));
}
return indices;
}
Is there a faster solution that avoids internal loop in List.indexOf()?
You can use Map:
Map<String, Integer> otherMap = new HashMap<>(other.size());
int index = 0;
for(String otherElem : other) {
otherMap.put(otherElem, index++);
}
And then:
for(String oneElem : one) {
Integer index = otherMap.get(oneElem);
indices.add(index == null ? -1 : index);
}
Doing so, you get the index directly instead of iterating on a potentially very big list each time you look for and index.
You can use a HashMap<String, Integer> that would map every character to its position. Then use HashMap method .containsKey() to find out, if a certain String is present in the field and .get() to find out the position.
HashMap<String, Integer> another;
for (String str : one) {
if (another.contains(str)) {
result.add(another.get(str));
} else {
result.add(-1);
}
}

Replace/Changing HashMap items during iteration

I get Concurrent Modification Exception when i try to remove an item from HashMap. I know that removing items during iteration through HashMap will trigger this exception , but i need to replace older item with new one. How can i do this ? Maybe to create a copy of countNumberOfEachCharacter HashMap , and whe iterate through original HashMap to remove item from copy HashMap ?
countNumberOfEachCharacter = new HashMap<Character,Character>();
if (countNumberOfEachCharacter.containsKey(word.charAt(i))) {
System.out.println("This character already exists");
for (Iterator it = countNumberOfEachCharacter.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Object key = entry.getKey();
Object value = entry.getValue();
if (key.equals(word.charAt(i))) {
int toIncrease = Integer.parseInt(value.toString());
toIncrease++;
System.out.println("key "+key);
System.out.println("increased "+toIncrease);
countNumberOfEachCharacter.remove(word.charAt(i));
char c = Character.forDigit(toIncrease, 10);
countNumberOfEachCharacter.put(word.charAt(i),c);
}
}
}
else {
System.out.println("First time found this character");
char c = Character.forDigit(1, 10);
countNumberOfEachCharacter.put(word.charAt(i),c);
System.out.println("Stored "+word.charAt(i)+" with count "+c);
}
While iterating over a Collection, you can only remove elements by using the Iterator#remove method. This is also documented in the class javadoc of HashMap
The iterators returned by all of this class's "collection view
methods" are fail-fast: if the map is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove method, the iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future
Furthermore for what you are trying to do (=update a value) you do not have to remove it. Just call put with that key and an updated value, which will update the value, as documented in the javadoc of the HashMap#put method
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
...but i need to replace older item with new one
I take it from "replace" (and from the code you've quoted) that the key remains the same, it's just the value that differs. If so, I don't believe calling setValue on Map.Entry objects causes a ConcurrentModificationException, so you could do that.
Update: Just tested it, and indeed, it works:
import java.util.*;
public class ReplaceMapEntryValue {
public static final void main(String[] args) {
Map m;
Iterator<Map.Entry> it;
Map.Entry entry;
// Create
m = new HashMap();
m.put("a", "alpha");
m.put("b", "beta");
// Update
it = m.entrySet().iterator();
while (it.hasNext()) {
entry = it.next();
if (entry.getKey() == "b") {
entry.setValue("bravo");
}
}
// Show
it = m.entrySet().iterator();
while (it.hasNext()) {
entry = it.next();
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
}
// Done
System.exit(0);
}
}
The whole point of a map is that you can lookup by key, you don't have to examine every entry.
Map<Character, AtomicInteger> countNumberOfEachCharacter = new TreeMap<Character, AtomicInteger>();
String word = "the quick brown fox jumps over the lazy dog";
for (int i = 0; i < word.length(); i++) {
AtomicInteger count = countNumberOfEachCharacter.get(word.charAt(i));
if (count == null)
countNumberOfEachCharacter.put(word.charAt(i), new AtomicInteger(1));
else
count.incrementAndGet();
}
System.out.println("Character count: " + countNumberOfEachCharacter);
prints
Character count: { =8, a=1, b=1, c=1, d=1, e=3, f=1, g=1, h=2, i=1, j=1, k=1, l=1, m=1, n=1, o=4, p=1, q=1, r=2, s=1, t=2, u=2, v=1, w=1, x=1, y=1, z=1}
However since you have a small, fixed number of possible characters you don't even need to use a Map
int[] countNumberOfEachCharacter = new int[Character.MAX_VALUE + 1];
String word = "the quick brown fox jumps over the lazy dog";
for (int i = 0; i < word.length(); i++)
countNumberOfEachCharacter[word.charAt(i)]++;
System.out.print("Character count: ");
for (int i = 0; i < countNumberOfEachCharacter.length; i++)
if (countNumberOfEachCharacter[i] > 0)
System.out.print(" " + (char) i + "=" + countNumberOfEachCharacter[i]);
System.out.println();
prints
Character count: =8 a=1 b=1 c=1 d=1 e=3 f=1 g=1 h=2 i=1 j=1 k=1 l=1 m=1 n=1 o=4 p=1 q=1 r=2 s=1 t=2 u=2 v=1 w=1 x=1 y=1 z=1

Categories

Resources