I have a list of some strings. I need to merge dublicates and add counter of duplicates. For example:
list1.add("Mom");
list1.add("Mom");
list1.add("Son");
list1.add("Son");
list1.add("Dad");
list1.add("Dad");
merge and add counter
and output needs to be like this:
Mom 2
Son 2
Dad 2
Also I need to sort this new list, but I think I can just use collections, to do that.
public static Map<String, Long> getValuesWithNumberOfOccurrences(
List<String> list) {
return list.stream()
.collect(
Collectors.groupingBy(i -> i, HashMap::new,
Collectors.counting()));
}
Use HashMap to keep duplicates:
HashMap<String, Integer> map = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
String text = list.get(i);
if(map.get(text) == null) {
map.put(text, 1);
} else {
map.put(text, map.get(text) + 1);
}
}
for (String text : map.keySet()) {
System.out.println(text + " " + map.get(text));
}
I'm assuming that the output order needs to respect the order in which the keys were first encountered. Fortunately the clever Java bods designed an object for that: java.util.LinkedHashMap.
To set up your storage object use
java.util.Map<String, Integer> map = new java.util.LinkedHashMap<>()
Note the fancy diamond notation.
Then, with name as a string, write something like
if (map.containsKey(name)){
map.put(key, map.get(key) + 1);
} else {
map.put(key, 1);
}
This could be optimised a little: you could rely on the fact that map.get(key) will be null if key is not present. This obviates the need for the containsKey call.
Finally, to output your values use something on the lines of
for (java.util.Map.Entry<String, Integer> entry : map.entrySet()){
/*ToDo - use entry.getKey() and entry.getValue()*/
}
If you want your output to be sorted on the keys then use a java.util.TreeMap instead. If the order of output is of no consequence to you then use a java.util.HashMap.
I need to merge duplicates and add counter of duplicates.
When duplicate stuff comes to mind, think of Set to isolate. As and when you try to add an element to set and the add method returns false, print the data with 2 count.
But when the entries can occur more than twice, then you need to keep a track of each entry's count until the very end. So use a map instead with each String as key and its count as value. That basically means, while adding a string to map:
Get it from the map
- if not null, then get its value, increment 1 and set its value again.
- if null, then add it to map with value=1
At the end, you can iterate and find count.
Related
I am trying to get first k values from a hashmap.
I know how to get all values from a hashmap and also how to iterate over all of them. Is there any short way to generate first k values from hashmap
for (Map.Entry<String, Integer> en : hmap.entrySet())
{
System.out.println("Key = " + en.getKey() + ", Value = " + en.getValue());
}
The notion of the first elements is undefined for Map interface. How it was mentioned in comments you can use LinkedHashMap or TreeMap where the first item make sense.
If you just want to get some limit number of map values, you could use stream api with limit:
hmap.entrySet().stream()
.limit(2)
.collect(Collectors.toList());
I am trying to figure out how to retrieve a value that is stored in an ArrayList, stored in a Hashmap.
Here's what I have:
HashMap<String, ArrayList<Record>> records = new HashMap<>();
The key in this hashmap is not what I am looking for. There is a method inside of the Record object called getRecordId() and I want to be able to evaluate whether or not this recordId, through an if statement, exists in the ArrayList.
Example:
if(records.values.exists(recordId)){ ...do something ...}
Essentially, I want to loop through all the values in the ArrayList to see if that record ID exists, and if it does, I will store the key and compute some things. How to I do this?
Edit: right after posting this question, I think I am on to something. How about this:
Set<Map.Entry<String, ArrayList<Record>>> entrySet = records.entrySet();
for(Map.Entry<String, ArrayList<Record>> data : entrySet)
{
for(Record entry : data.getValue())
{
if(recordId.equals(entry.getRecordId()))
{
// Do something here
return "";
}
}
}
I need to leave the loops if the record ID has been found, because record IDs are unique.
You can use here Hashmap.entrySet() to get the list of all the keys, and iterate through that key set, and check if recordId exists in the ArrayList for that particular iteration, then store the key and do your computations.
If you are not sure about the syntax and usage of entrySet then you can look into it here - https://www.geeksforgeeks.org/iterate-map-java/
for (Map.Entry<String, ArrayList> data : records) {
ArrayList list = (ArrayList) data.getValue();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(recordId)) {
// do something
}
}
}
If you are using Java 8 you can use stream:
//List of keys which contains your desired Record at it's value(ArrayList)
List<String> requiredListOfKeys = records.keySet().stream()
.filter(x -> records.get(x)
.contains(record))
.collect(Collectors.toList());
One way to go would be to stream the map values, and for each value (which is a list), stream it and find the first Record instance that matches your search criteria. Then, if such record was found, do whatever you want to do with it:
boolean found = records.values().stream()
.flatMap(List::stream) // or .flatMap(list -> list.stream())
.filter(entry -> recordId.equals(entry.getRecordId()))
.findFirst()
.ifPresent(entry -> {
// do something with the found record
});
You can use the following syntax :
records.forEach((k, v) -> {
if (v.contains(recordId)) {
// do something with 'k'
}
});
Here we are iterating over the map using forEach. The k stands for the key and the v stands for the value. You can also achieve the same using the entrySet
records.entrySet().forEach(e -> {
if (e.getValue().contains(recordId)) {
// do something with 'e.getKey()'
}
});
I need a HashMap, which the key is String and value is Set, like:
Key: "a", Value: {"a","b","c"....}
Key: "b", Value: {"a,","d"....}
...
But I do not know how many keys in total, it depends on the result from other method.
So basically, here is the method looks like: (map could be field)
public void mapKeyValue(int numbersOfKey, HashMap map){
//some code
}
So if I write the code like this:
public void mapKeyValue(int numbersOfKey, HashMap map){
for (int i = 0; i < numbersOfKey; i++){
Set<String> set = new HashSet<String>();
set.add("some strings");// we can add some strings here
map.put("OneString", set);
}
}
After the method, I will get nothing because I will lose all the Set object created by the method, so I cannot get the Set by calling map.get("OneString").
So what should I do if I want to get that hashMap?
There are a number of issues with your code, but I suggest the following approach.
In your case, it looks like you have a Map<String, Set<String>> which is a map of String keys to a set of Strings.
If that's what you were after, I suggest that you
check if the key has a value. If not add an empty set for the key to the surrounding map.
Fetch the set from the map by it's key.
add or remove any desired values from the set
Note that your code as it is written, always replaces the Set stored with the key "OneString" meaning that regardless of value "numbersOfKey" you are really just rebuilding the set at the single key "OneString" numbersOfKey times.
You probably want to do something like
public void addToSet(String setName, String value) {
if (!sets.containsKey(setName)) {
sets.put(setName, new HashSet<String>());
}
Set<String> values = sets.get(setName);
values.add(value);
}
This block assumes you have somewhere in the class a member variable like
private Map<String, Set<String>> sets = new HashMap<>();
Note that this code is an idea, and not production code. In the real world, what you add probably should eventually be removed at some point in time. As such, you want to have a facility to remove specific values, or entire sets of values along with their keys at some future point of your program's execution.
you can not do that?
public HashMap<String, Set<String>> mapKeyValue(int numbersOfKey){
HashMap<String, Set<String>> map = new HashMap<>();
for (int i = 0; i < numbersOfKey; i++){
Set<String> set = new HashSet<String>();
set.add("some strings" + "" + i);// we can add some strings here
map.put("OneString", set);
}
return map;
}
I would suggest using the Apache Commons Collection MultiValueMap instead of creating a Set each time. Both work just fine, but there is a Map that does all of that for you and it's based on a HashMap, keeping your constant time access. Javadoc here:
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/MultiValueMap.html
Something like this...
public void someOtherMethod() {
// Assuming the Map is created and used somewhere outside the mapKeyValue method. Otherwise it should be instantiated inside the mapKeyValue method
MultiValueMap<String, String> map = new MultiValueMap<>();
//2 is an arbitrary, made up number that you select somehow
mapKeyValue(2, map);
//Access the values of the map dynamically without knowing how many keys there are
for (String key : map.keySet()) {
System.out.print(key + " : ");
for (String value : map.getCollection(key)) {
System.out.print(value + ", ");
}
}
}
public MultiValueMap<String, String> mapKeyValue(int numbersOfKey, MultiValueMap<String, String> map){
for (int i = 0; i < numbersOfKey; i++){
//We need to create a unique key here, so let's use 'i'
//There are several ways to skin the cat and get the int to String
//Also want to create unique values, but that's up to you, they're not required to be unique
map.put(Integer.toString(i), Integer.toString(i) + "a");
map.put(Integer.toString(i), Integer.toString(i) + "b");
map.put(Integer.toString(i), Integer.toString(i) + "c");
}
//At this point, the map has in it the following key : value pairs
//"0" : ["0a", "0b", "0c"]
//"1" : ["1a", "1b", "1c"]
//"2" : ["2a", "2b", "2c"]
//Not technically required to return the map IFF the map is instantiated outside the method
return map;
}
I have Map in Java
Map<String, List<String>> Collections;
String - a parents to ExpandtableList
List -a children to Expandtable List
Example Values
<"12" , "5,6,7,8">
<"15" , "4,6,2,8">
<"17" , "1,6,7,8">
<"8" , "5,6,6,8">
I'd like to get second parent and atribute to temporary String variable.(it is a "17") How can i refer to 2-nd parent and return value ?
There is no ordering in HashMap. If you want to focused on Order with Map you should use LinkedHashMap.
Use LinkedHashMap instead of HashSet. LinkedHashMap will maintain the insertion order.
Well, if you want "17" then you can just write map.get("17") to get the List.
Java doesnt keep track of the order here as it uses a Set to store the data. map.keySet() will return you a set you can iterate through.
You can HOPE that 17 falls under the natural ordering that Java does and do something like this.
HashMap<String, List<String>> map = new HashMap<>();
int count = 0;
for (String key : map.keySet()) {
count++;
if (count == 2)
return map.get(key);
}
If you want to retain an order in a Map, your usual choice would be a LinkedHashMap. With a linked hash map, you do however still not have direct access to an entry by its index. You would need to write a helper function:
static List<String> indexList(LinkedHashMap<String, List<String>> map, int index) {
int i = 0;
for(Map.Entry<String, List<String>> entry : map.entrySet()) {
if(i++ == index) {
return entry.getValue();
}
}
throw new IndexOutOfBoundException();
}
When using maps that point to a list, you might also be interested in using Guava's Multimap.
I have a list gotitems.
ArrayList<String> gotitems = new ArrayList<String>();
i need to put that list in a hashmap called map.
Map<String,String> map = new HashMap<String,String>();
i had tried this :
for(String s:gotitems){
map.put("a",s);
}
gotitems contains :
First
Second
Third
But the output of :
System.out.println(map.values());
gives :
Third
Third
Third
i had even tried this :
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
but this is also not working.
What am i doing wrong here ?
As per Map put(K,V) method docs
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value.
You are ovverriding the key each time here .
for(String s:gotitems){
map.put("a",s);
}
change the key each time and try like
for(String s:gotitems){
map.put(s,s);
}
This is because you are putting all the items in the map against the same key "a"
map.put("a");
You need to store each element against a unique key so add something like this:
int count = 0;
for(String s:gotitems){
map.put("a" + count,s);
count++;
}
You are trying to put three Strings in the map under the same key "a". Try to use unique keys for your values.
You're putting all your items in the Map with the same key: "a".
You should have a unique String key for each value.
For instance:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Map<String, String> map = new LinkedHashMap<String, String>();
for (String s: list) {
map.put(s, s);
}
System.out.println(map);
Output:
{one=one, two=two, three=three}
Note the LinkedHashMap here: it maintains the order in which you put your key/value pairs.
Edit Of course if your List does not have unique values, moving its values as keys to a Map will overwrite some of the Map's values. In that case you want to ensure your List has unique keys first, or maybe use a Map<Integer, String> with the index of the List's value as key to the Map, and the actual List value as value to the Map.
When you write
for(String s:gotitems){
map.put("a",s);
}
you will trash any existing entry in the map held against the key "a". So after your iteration, your map will contain just one entry corresponding to the last iterated value in gotitems.
To use a map effectively you need to consider what your keys will be. Then use map.put(myKeyForThisItem, s) instead. If you don't have an effective scheme for the keys then using a map is pointless as one tends to use the keys to extract the corresponding values.
As for your second approach, it would be helpful if you could define "it is not working" a little clearer: perhaps iterate through the map and print the keys and values.
Please note that in a map, a key can point to at most one value. In your case, you are doing the following mappings:
"a" -> "one"
then you overwrite it as
"a" -> "two"
then you overwrite it as
"a" -> "three"
remember: a key can point to at most one value. However, a value can be pointed at by multiple keys.
This is wrong:
for(String s:gotitems){
map.put("a",s);
}
Since you are using "a" common key for all values, last inserted key-value pair would be preserved, all previous ones would be overridden.
This is also not correct:
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
you are putting n*n times into map, though you want only n (gotitems.size()) items into map.
First decide on key which you want to use in map, copying List into Map one approach could be use index as key:
for(int j=0;j<gotitems.size();j++){
map.put("KEY-"+j,gotitems.get(j));
}
Output should be:
KEY-0 First
KEY-1 Second
KEY-2 Third
I have reproduce your codes. The problem is that you are assigning the same key to different value. This should work.
import java.util.*;
public class testCollection{
public static void main(String[] args){
ArrayList<String> gotitems = new ArrayList<String>();
gotitems.add("First");
gotitems.add("Second");
gotitems.add("Third");
Map<String,String> map = new HashMap<String,String>();
String x = "a";
int i = 1;
for(String s:gotitems){
map.put(x+i,s);
i++;
}
System.out.println(map);
}
}