I have bunch of log files and I want to process them in java, but I want to sort them first so I can have more human readable results.
My Log Class :
public class Log{
//only relevant fields here
private String countryCode;
private AccessType accessType;
...etc..
}
AccessType is Enum, which has values WEB, API, OTHER.
I'd like to group Log objects by both countryCode and accessType, so that end product would be log list.
I got this working for grouping Logs into log list by countryCode like this :
public List<Log> groupByCountryCode(String countryCode) {
Map<String, List<Log>> map = new HashMap<String, List<Log>>();
for (Log log : logList) {
String key = log.getCountryCode();
if (map.get(key) == null) {
map.put(key, new ArrayList<Log>());
}
map.get(key).add(log);
}
List<Log> sortedByCountryCodeLogList = map.get(countryCode);
return sortedByCountryCodeLogList;
}
from this #Kaleb Brasee example :
Group by field name in Java
Here is what I've been trying for some time now, and really stuck now ..
public List<Log> groupByCountryCode(String countryCode) {
Map<String, Map<AccessType, List<Log>>> map = new HashMap<String, Map<AccessType, List<Log>>>();
AccessType mapKey = null;
List<Log> innerList = null;
Map<AccessType, List<Log>> innerMap = null;
// inner sort
for (Log log : logList) {
String key = log.getCountryCode();
if (map.get(key) == null) {
map.put(key, new HashMap<AccessType, List<Log>>());
innerMap = new HashMap<AccessType, List<Log>>();
}
AccessType innerMapKey = log.getAccessType();
mapKey = innerMapKey;
if (innerMap.get(innerMapKey) == null) {
innerMap.put(innerMapKey, new ArrayList<Log>());
innerList = new ArrayList<Log>();
}
innerList.add(log);
innerMap.put(innerMapKey, innerList);
map.put(key, innerMap);
map.get(key).get(log.getAccessType()).add(log);
}
List<Log> sortedByCountryCodeLogList = map.get(countryCode).get(mapKey);
return sortedByCountryCodeLogList;
}
I'm not sure I know what I'm doing anymore
Your question is confusing. You want to sort the list, but you are creating many new lists, then discarding all but one of them?
Here is a method to sort the list. Note that Collections.sort() uses a stable sort. (This means that the original order of items within a group of country code and access type is preserved.)
class MyComparator implements Comparator<Log> {
public int compare(Log a, Log b) {
if (a.getCountryCode().equals(b.getCountryCode()) {
/* Country code is the same; compare by access type. */
return a.getAccessType().ordinal() - b.getAccessType().ordinal();
} else
return a.getCountryCode().compareTo(b.getCountryCode());
}
}
Collections.sort(logList, new MyComparator());
If you really want to do what your code is currently doing, at least skip the creation of unnecessary lists:
public List<Log> getCountryAndAccess(String cc, AccessType access) {
List<Log> sublist = new ArrayList<Log>();
for (Log log : logList)
if (cc.equals(log.getCountryCode()) && (log.getAccessType() == access))
sublist.add(log);
return sublist;
}
If you're able to use it, Google's Guava library has an Ordering class that might be able to help simplify things. Something like this might work:
Ordering<Log> byCountryCode = new Ordering<Log>() {
#Override
public int compare(Log left, Log right) {
return left.getCountryCode().compareTo(right.getCountryCode());
}
};
Ordering<Log> byAccessType = new Ordering<Log>() {
#Override
public int compare(Log left, Log right) {
return left.getAccessType().compareTo(right.getAccessType());
}
};
Collections.sort(logList, byCountryCode.compound(byAccessType));
You should create the new inner map first, then add it to the outer map:
if (map.get(key) == null) {
innerMap = new HashMap<AccessType, List<Log>>();
map.put(key, innerMap);
}
and similarly for the list element. This avoids creating unnecessary map elements which will then be overwritten later.
Overall, the simplest is to use the same logic as in your first method, i.e. if the element is not present in the map, insert it, then just get it from the map:
for (Log log : logList) {
String key = log.getCountryCode();
if (map.get(key) == null) {
map.put(key, new HashMap<AccessType, List<Log>>());
}
innerMap = map.get(key);
AccessType innerMapKey = log.getAccessType();
if (innerMap.get(innerMapKey) == null) {
innerMap.put(innerMapKey, new ArrayList<Log>());
}
innerMap.get(innerMapKey).add(log);
}
Firstly, it looks like you're adding each log entry twice with the final line map.get(key).get(log.getAccessType()).add(log); inside your for loop. I think you can do without that, given the code above it.
After fixing that, to return your List<Log> you can do:
List<Log> sortedByCountryCodeLogList = new ArrayList<Log>();
for (List<Log> nextLogs : map.get(countryCode).values()) {
sortedByCountryCodeLogList.addAll(nextLogs);
}
I think that code above should flatten it down into one list, still grouped by country code and access type (not in insertion order though, since you used HashMap and not LinkedHashMap), which I think is what you want.
Related
I am trying to sort a list based on sort key and sort order I receive from an API.
For example,
I have a list with sortkey and sortorder and based on that I need to sort.
List<SortList> sortlist;
I have a list of an object :
List<Employee> employee;
I am able to sort using
Collections.sort(sourceList, Comparator
.comparing(Employee::getAge).reversed()
.thenComparing(Employee::getCount));
But i need to check the sortfeild on a condition and based on that only the field is considered for sorting.
ex:
if(sortkey = "name")
sortbythatkey from sortlist by the sort order
if (sortkey = "place")
sortbythat key from sortlist by the sort order
So here if sortlist has both name and place then it should sort by both key and order
Any idea how could i achieve this?
Sort List contains:
{
"sortKey":"name",
"sortOrder":"ASC"
},
{
"sortKey":"place",
"sortOrder":"DESC"
}
Requirement is to chain them together like ORDER BY in SQL
Assuming that sortlist is a list of SortCriteria, which is a class like this:
class SortCritera {
private String key;
private String order;
public String getKey() {
return key;
}
public String getOrder() {
return order;
}
// constructors, setters...
}
You first need a HashMap<String, Comparator<Employee>> to store all the corresponding comparators for each possible key:
HashMap<String, Comparator<Employee>> comparators = new HashMap<>();
comparators.put("name", Comparator.comparing(Employee::getName));
comparators.put("age", Comparator.comparing(Employee::getAge));
// ...
Then you can loop through the sortlist and keep calling thenComparing:
Comparator<Employee> comparator = comparators.get(sortlist.get(0).getKey());
if (sortlist.get(0).getOrder().equals("DESC")) {
comparator = comparator.reversed();
}
for(int i = 1 ; i < sortlist.size() ; i++) {
if (sortlist.get(i).getOrder().equals("DESC")) {
comparator = comparator.thenComparing(comparators.get(sortlist.get(i).getKey()).reversed());
} else {
comparator = comparator.thenComparing(comparators.get(sortlist.get(i).getKey()));
}
}
// now you can sort with "comparator".
As Holger has suggested, you can use the Stream API to do this as well:
sortlist.stream().map(sc -> {
Comparator<Employee> c = comparators.get(sc.getKey());
return sc.getOrder().equals("DESC")? c.reversed(): c;
}).reduce(Comparator::thenComparing)
.ifPresent(x -> Collections.sort(originalList, x));
You can create a method which when passed the sort key, you provide the proper Comparator:
public Comparator<Employee> getComparator(String sortKey) {
if("name".equals(sortKey)) {
return Comparator.comparing(Employee::getName);
} else if ("place".equals(sortKey) {
return Comparator.comparing(Employee::getPlace);
} else {
throw new IllegalArgumentException();
}
}
To call it it would simply be:
Collections.sort(sourceList, getComparator(sortKey).reversed()
.thenComparing(Employee::getCount));
While you could also write your own, I find it is better to delegate the "standard" parts and simply write the part that differs from this.
If you find yourself having many such sort keys, then a more suitable means to do this would be to use a map:
private static final Map<String, Comparator<Employee>> COMPARE_MAP = new HashMap<>() {{
put.("name", Comparator.comparing(Employee::getName));
put.("place", Comparator.comparing(Employee::getPlace));
}});
public Comparator<Employee> getComparator(String sortKey) {
if(COMPARE_MAP.containsKey(sortKey)) {
return COMPARE_MAP.get(sortKey);
} else {
throw new IllegalArgumentException();
}
}
Reflection is also an option, but I would be cautious to use reflection unless it becomes impractical to do otherwise. In that case, you could create your own annotation to determine which fields of class Employee can be used for sorting.
I am really new to Java and I am trying to implement something using Hashmap.
The following code is what I declared first:
private HashMap<String, TreeMap<Object, Object>> submissions = new HashMap<String, TreeMap<Object, Object>>();;
And,
public Submission add(String unikey, Date timestamp, Integer grade) {
// check the argument
if(unikey == null || timestamp == null || grade == null) {
throw new IllegalArgumentException("Null argument detected\n");
}
}
this is what I am writing at the moment. Assuming that there are items called "person", "data" and "grade". Can someone please tell me how to put them in the nested hashmap? I finished writing the getter and setter for each of the items in another class called, MySubmissions.
The Submission is an interface written in another class that contain the following methods:
public String getPerson();
public Date getTime();
public Integer getGrade();
What I want to achieve is that, for example,
?.add("aaaa1234", df.parse("2016/09/03 09:00:00"), 10);
?.add("aaaa1234", df.parse("2016/09/03 16:00:00"), 20);
?.add("cccc1234", df.parse("2016/09/03 16:00:00"), 30);
?.add("aaaa1234", df.parse("2016/09/03 18:00:00"), 40);
Thanks!
(what I exactly want to achieve is, I want to add data into the hashmap. And then using another method called, getBestGrade, I want to get the best graded person among the list but I just want to know how to store into the hashmap first using put and get...)
Create an entity
public class Submission {
private Date timestamp;
private Integer grade;
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Submission that = (Submission) o;
if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null) return false;
return grade != null ? grade.equals(that.grade) : that.grade == null;
}
#Override
public int hashCode() {
int result = timestamp != null ? timestamp.hashCode() : 0;
result = 31 * result + (grade != null ? grade.hashCode() : 0);
return result;
}
}
Create a HashMap
private HashMap<String, Submission> map = new HasMap<>();
Do add
map.add("key", new Submission());
I think he wants to know how to store more than one Submission for each Person. You can do something like this:
import java.util.Date;
import java.util.HashMap;
import java.util.TreeMap;
public final class BestGrade
{
private static final HashMap<String, TreeMap<Date, Integer>> SUBMISSIONS = new HashMap<String, TreeMap<Date, Integer>>();
private BestGrade()
{}
public static void main(final String[] args)
{
// How to add
add("Person1", new Date(), Integer.valueOf(1));
add("Person1", new Date(), Integer.valueOf(10));
add("Person1", new Date(), Integer.valueOf(20));
add("Person2", new Date(), Integer.valueOf(1));
add("Person3", new Date(), Integer.valueOf(30));
add("Person3", new Date(), Integer.valueOf(40));
// How to get best grade
final Integer bestGradePerson1 = getBestGrade("Person1");
final Integer bestGradePerson3 = getBestGrade("Person2");
final Integer bestGradePerson2 = getBestGrade("Person3");
System.out.println("Bestgrade Person1: " + bestGradePerson1);
System.out.println("Bestgrade Person2: " + bestGradePerson2);
System.out.println("Bestgrade Person3: " + bestGradePerson3);
}
public static void add(final String key, final Date timestamp, final Integer grade)
{
// TODO the same for timestamp and grade
if (key == null || key.trim().isEmpty()) {
throw new IllegalArgumentException("key must not be null");
}
// Get
TreeMap<Date, Integer> submission = SUBMISSIONS.get(key);
// Create your treemap if not already exists, before adding new value to avoid NullPointerException
if (submission == null) {
submission = new TreeMap<Date, Integer>();
SUBMISSIONS.put(key, submission);
}
submission.put(timestamp, grade);
}
public static Integer getBestGrade(final String key)
{
Integer bestGrade = null;
final TreeMap<Date, Integer> submission = SUBMISSIONS.get(key);
if (submission == null) {
// When no submission available, return null or any other value you wish to show there is no best grade
return bestGrade;
}
for (final Integer grade : submission.values()) {
if (bestGrade == null) {
bestGrade = grade;
}
// Set new grade when values is higher than before
else if (bestGrade.intValue() < grade.intValue()) {
bestGrade = grade;
}
}
return bestGrade;
}
}
I'm just going to describe how to use a map of maps -- it's up to you to decide whether this is what you actually want to use. I'm going to use classes called A,B,C etc. -- you can substitute your own, including String or Submission if you like.
Make sure you have a firm understanding of a single-level Map before you tackle this -- how equals() and hashCode() are necessary for HashMap etc.
You can define a map of maps much as you have done:
Map<A, ? extends Map<B,C>> mapOfMaps;
In general, give variables a type of Map rather than HashMap or TreeMap -- you normally don't need any of the more specific methods of the implementation classes. You can always change up if you do. The ? extends Map<> part allows your map-of-maps to contains arbitrary implementations of Map.
You can instantiate this like this:
Map<A, ? extends Map<B,C>> mapOfMaps = new HashMap<>();
// or with explicit (unnecessary) type declarations:
Map<A, ? extends Map<B,C>> mapOfMaps = new HashMap<A, ? extends Map<B,C>>();
Now you have an empty map-of-maps. You can add a map to it:
Map<B,C> map = new HashMap<>();
mapOfMaps.put(new A(1), map);
Now you have a map-of-maps containing one empty map. Or you could add a map containing something:
Map<B,C> map = new HashMap<>();
map.put(b, c);
mapOfMaps.put(a, map);
Plausibly, you want to add items to a Map<B,C> when you don't know whether it exists. There's no short-cut here - you have to do:
void addToMapOfMaps(A a, B b, C c) {
Map<B,C> map = mapOfMaps.get(a);
if(map == null) {
map = new HashMap<>();
mapOfMaps.put(a,map);
}
map.put(b,c);
}
Note that this has problems if multiple threads are doing it at the same time.
Likewise if you're just reading, you have to handle missing elements at both levels:
C get(A a, B b) {
Map<B,C> map = mapOfMaps.get(a);
if(map == null) {
return null;
}
return map.get(b);
}
(Or more compactly)
C get(A a, B b) {
Map<B,C> map = mapOfMaps.get(a);
return map == null ? null : map.get(b);
}
I'm new in Java and I want to add a list into a BinarySearchTree with an Integer as a Key and a List as value.
So I need every element of a list that I want to add and add to the BST.
I'm using BST because I need to sort it with the key.
In the class Group I have a method called getNumber() that return the number os elements in the that group and the key will be the number of elements of a Group.
Right now I have this and I don't know how to continue. groups.iterator() is just to iterate every group of a list.
orderedGroups is a BinarySearchTree <Integer, List<Group>>().
EDIT:
I have this.
public Iterator<Entry<Integer, List<Group>>> listWarriors() throws NoGroupsException {
if(!isThereGroup())
throw new NoGroupsException();
Iterator<Entry<String, Group>> it = groups.iterator();
List<Group> listGroup = new DoublyLinkedList<Group>();
int j = 0;
while(it.hasNext()) {
listGroup.add(j, it.next().getValue());
j++;
}
for(int i = 0; i<j; i++) {
List<Group> list = orderedGroups.find(listGroup.get(i).getNumber());
if(list == null) {
list = new DoublyLinkedList<Group>();
list.addFirst(listGroup.get(i));
orderedGroups.insert(-(listGroup.get(i).getNumber()), list);
}
else {
if(list.equals(listGroup.get(i))) {
list.addFirst(listGroup.get(i));
}
}
}
return orderedGroups.iterator();
}
OrderedDictionary > orderedGroups = new BinarySearchTree>();
And a group is added by doing this.
public void addGroup(String idGrupo, String nome) throws GroupAlreadyExistsException {
if(searchGroup(idGrupo))
throw new GroupAlreadyExistsException();
group = new GroupClass(idGrupo, nome);
groups.insert(idGrupo.toLowerCase(), group);
}
I have all these in a Class called System.
It looks like you think you have to roll your own iterator in order to enumerate your list. Not necessary.
I can't tell exactly what you are trying to do here, but maybe the below will help, which just demonstrates how to iterate a list.
void addListToGroup(List<Foo> myList, List<group> myGroups) {
for (Foo foo : myList) {
Object value=myList.someFunction();
Group newGroup = new Group(value);
myGroups.add(newGroup);
}
}
I'm not sure I understand fully what you're trying to do, and why you're not using LinkedList and TreeMap, but I see a few issues in your code:
your for loop makes i start at 1 whereas list indices start at 0,
building listGroup seems useless: you could directly build orderedGroups
orderedGroups is not modified in your code (orderedGroupsByC is though)
UPDATE:
What if you did this:
Iterator<Entry<String, Group>> it = groups.iterator();
while (it.hasNext()) {
Group group = it.next();
List<Group> list = orderedGroups.find(group.getNumber());
if (list == null) {
list = new DoublyLinkedList<Group>();
list.addFirst(group);
orderedGroups.insert(group.getNumber(), list);
} else {
list.addFirst(group);
}
}
I have a class called LineUp, it is an ArrayList of a class called Event. An Event has three values a String Act, a Venue (it's own class), and an int Session.
An Event might be declared like this.
Event e1 = new Event("Foo Fighters", northstage, "1")
LineUp is an ArrayList, Event being elements like e1.
In my LineUp class I have to make an invariant that checks that every Event contained within the ArrayList lineup has a unique Venue and Session. Because this assignment requires that I follow specification exactly, it is irrelevant whether the combination of Act, Venue and Session is unique, to follow specification I must /only/ ensure that Venue and Session are unique.
How do I check for duplicates but only of specific values within an ArrayList?
Thank-you.
If you only need to check if there are duplicates (considering venue-session pairs), you could create a helper Pair class with only the attributes that matter in this specific case. Then map the events to Pair objects, remove the duplicates and check if the size is the same.
You could, for example, create a nested class inside LineUp:
class LineUp {
private List<Event> events = new ArrayList<>();
private static final class Pair<U, V> {
final U first;
final V second;
Pair(U first, V second) {
this.first = first;
this.second = second;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Pair)) {
return false;
}
Pair<U, V> that = (Pair<U, V>) o;
return Objects.equals(this.first, that.first)
&& Objects.equals(this.second, that.second);
}
#Override
public int hashCode() {
return Objects.hash(this.first, this.second);
}
}
// rest of the LineUp class
}
Then create a method that return false if there are any duplicates:
public boolean duplicateVenueSessions() {
// Map each Event to a Pair<Venue, Integer> and remove the duplicates
long numDistinct = this.events.stream()
.map(e -> new Pair<>(e.venue, e.session))
.distinct()
.count();
// return false if the original number of events is different from the
// number of distinct events considering only venue and session values
return this.events.size() != numDistinct;
}
If can't use Java 8, you could use a Set instead:
public boolean duplicateVenueSessions() {
Set<Pair<String, Integer>> distinct = new HashSet<>();
for (Event e : this.events) {
Pair<String, Integer> venueSession = new Pair<>(e.venue, e.session);
if (distinct.contains(venueSession)) {
return true;
}
distinct.add(venueSession);
}
return false;
}
If I understand everything correctly you can use Map in a method to store values
Map<Map<Venue, Integer>, Act> lineup = new HashMap<>();
it incorporated uniqueness of Venue-Session pair.
However as Venue is your own class, you will have to implement equals() and hashCode() methods for Venue in order for this solution to work
EDIT:
what I meant wa something like this:
Map<Map<Integer, Venue>,String> uniqueMap = new HashMap<>();
for (Event event: events) { // assuming events is ArrayList
Map<Integer, Venue> sessionVenueMap = new HashMap<>();
sessionVenueMap.put(event.getSession(), event.getVenue());
//check if we stored this pair in our cool map
if (uniqueMap.get(sessionVenueMap) == null) {
//if not
//store this in our uniqieMap in our method
uniqueMap.put(sessionVenueMap, event.getAct);
sessionVenueMap.put(event.getSession(), event.getVenue);
} else {
// if map has this pair
// then it is not unique
return false;
}
venueSessionMap.put(.getVenue(); event.getSession();
}
return true;
code is not tested though, but you get the general idea, although it seems quite complex. probably there is a better solution
I have been running into this problem sometimes when programming.
Imagine I have a table of data with two columns. The first column has strings, the second column has integers.
I want to be able to store each row of the table into a dynamic array. So each element of the array needs to hold a string and an integer.
Previously, I have been accomplishing this by just splitting each column of the table into two separate ArrayLists and then when I want to add a row, I would call the add() method once on each ArrayList. To remove, I would call the remove(index) method once on each ArrayList at the same index.
But isn't there a better way? I know there are classes like HashMap but they don't allow duplicate keys. I am looking for something that allows duplicate entries.
I know that it's possible to do something like this:
ArrayList<Object[]> myArray = new ArrayList<Object[]>();
myArray.add(new Object[]{"string", 123});
I don't really want to have to cast into String and Integer every time I get an element out of the array but maybe this is the only way without creating my own? This looks more confusing to me and I'd prefer using two ArrayLists.
So is there any Java object like ArrayList where it would work like this:
ArrayList<String, Integer> myArray = new ArrayList<String, Integer>();
myArray.add("string", 123);
Just create simple POJO class to hold row data. Don't forget about equals and hashCode and prefer immutable solution (without setters):
public class Pair {
private String key;
private Integer value;
public Pair(String key, Integer value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public Integer getValue() {
return value;
}
// autogenerated
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Pair)) return false;
Pair pair = (Pair) o;
if (key != null ? !key.equals(pair.key) : pair.key != null) return false;
if (value != null ? !value.equals(pair.value) : pair.value != null) return false;
return true;
}
#Override
public int hashCode() {
int result = key != null ? key.hashCode() : 0;
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
}
Usage:
List<Pair> list = new ArrayList<Pair>();
list.add(new Pair("string", 123));
Note: in other languages there are build-in solutions for it like case-classes and tuples in Scala.
Create a Row class that holds the data.
package com.stackoverflow;
import java.util.ArrayList;
import java.util.List;
/**
* #author maba, 2012-10-10
*/
public class Row {
private int intValue;
private String stringValue;
public Row(String stringValue, int intValue) {
this.intValue = intValue;
this.stringValue = stringValue;
}
public int getIntValue() {
return intValue;
}
public String getStringValue() {
return stringValue;
}
public static void main(String[] args) {
List<Row> rows = new ArrayList<Row>();
rows.add(new Row("string", 123));
}
}
You can create very simple object, like :
public class Row{
private String strVal;
private Integer intVal;
public Row(String s, Integer i){
strVal = s;
intVal = i;
}
//getters and setters
}
Then use it as follows :
ArrayList<Row> myArray = new ArrayList<Row>();
myArray.add(new Row("string", 123));
Map is the option if you are sure that any one value among integer or string is unique. Then you can put that unique value as a key. If it is not true for your case, creating a simple POJO is best option for you. Infact, if in future, there a chance to come more values (columns) per row then also using a POJO will be less time consuming. You can define POJO like;
public class Data {
private int intValue;
private String strValue;
public int getIntValue() {
return intValue;
}
public void setIntValue(int newInt) {
this.intValue = newInt;
}
public String getStrValue() {
return strValue;
}
public void setStrValue(String newStr) {
this.strValue = newStr;
}
And in the class you can use it like;
ArrayList<Data> dataList = new ArrayList<Data>();
Data data = new Data();
data.setIntValue(123);
data.setStrValue("string");
dataList.add(data);
You should create a class (e.g. Foo) that contains an int and a String.
Then you can create an ArrayList of Foo objects.
List<Foo> fooList = new ArrayList<Foo>();
This is called a map my friend. It is similar to a dictionary in .net
http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
HashMap my be the class you are looking for assuming "string" going to different for different values. Here is documentation on HashMap
Example:
HashMap<String, Integer> tempMap = new HashMap<String, Integer>();
tempMap.put("string", 124);
If you need to add more than one value, you may create HashMap<String, ArrayList> like that.
you can use google collection library Guava there is a Map called Multimap. It is collection similar to a Map, but which may associate multiple values with a single key. If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values.
Use Map to solve this problem:
Map<String, Integer> map = new HashMap<String, Integer>();
Eg:
map.put("string", 123);