Reputation: 455
I'm looking out to print the index value of a respective character as many times as it would appear using HashMap
.
For example, let's say I have String str = "Hello World"
. The program as of now displays the occurence of characters via {d=1, W=1, e=1, r=1, o=2, l=3, H=1}
.
What I intend to achieve as resultset is {d=[9], o=[4, 6], r=[7], W=[5], H=[0], l=[2, 3, 8], e=[1]}
where *=[*]
represents key=[indexValue]
.
(The whitespace character is not to be taken into consideration in the final resultSet.)
import java.util.HashMap;
import java.util.Map;
public class ConcordanceOfStrings {
public static void main(String[] args) {
String str = "Hello World";
//code to remove whitespaces
String newStr = str.replaceAll(" ", "");
Map<Character, Integer> numCount = new HashMap<Character, Integer>(Math.min(newStr.length(), 26));
System.out.println("The count is: ");
for(int i=0; i<newStr.length(); i++){
char charAt = newStr.charAt(i);
if(!numCount.containsKey(charAt)){
numCount.put(charAt, 1);
}
else{
numCount.put(charAt, numCount.get(charAt)+1);
}
}
System.out.println(numCount);
}
}
Upvotes: 0
Views: 2843
Reputation: 811
You need something more than just Map you need something like Map>. Here is a example of a modification to your algorithm:
Map<Character, List<Integer>> positions = new HashMap<>();
Map<Character, Integer> numCount = new HashMap<Character, Integer>(Math.min(newStr.length(), 26));
for (int i = 0; i < newStr.length(); i++) {
char charAt = newStr.charAt(i);
if (!numCount.containsKey(charAt)) {
numCount.put(charAt, 1);
}
else {
numCount.put(charAt, numCount.get(charAt) + 1);
}
if(!positions.containsKey(charAt)){
List<Integer> cPosition = new LinkedList<>();
cPosition.add(i);
positions.put(charAt, cPosition);
}
else{
List<Integer> cPosition = positions.get(charAt);
cPosition.add(i);
//positions.put(charAt, cPosition); because of references there is no need to do this
}
}
Upvotes: 2
Reputation: 137289
You're very close. Right now, you are storing the result in a Map<Character, Integer>
, so a map from each character to the number of times it appears in the String.
To store all the indexes where the character appears, you need to have a Map<Character, List<Integer>>
: each character will be mapped to a list of integers, which will be the list of the indexes where this character appears.
In your current code, you just need to adapt the logic that populates the map:
if(!numCount.containsKey(charAt)){
numCount.put(charAt, new ArrayList<>(Arrays.asList(i))); // <-- we store a list containing the first index i
// numCount.put(charAt, 1);
} else{
numCount.get(charAt).add(i); // <-- we add to the existing list the index i
// numCount.put(charAt, numCount.get(charAt)+1);
}
In the case where the map doesn't contain the character, we initialize the mapping with a list containing the first index i
. Arrays.asList(i)
returns a fixed-size list so I wrapped it in another ArrayList
.
In the case where the map already contains the character, we just need to get the current list of indexes and add the one we just found.
If you are using Java 8, your whole code could be written more simply with Streams:
Map<Character, List<Integer>> numCount =
IntStream.range(0, str.length())
.filter(i -> str.charAt(i) != ' ')
.boxed()
.collect(Collectors.groupingBy(
i -> str.charAt(i),
Collectors.mapping(v -> v - 1, Collectors.toList())
));
Upvotes: 3