storing multiple values in a map against single key - java

I have the following file named ght.txt in my c: and it contains the following data
Id|ytr|yts
1|W|T
2|W|T
3|W|T
Now the thing is that positions of this columns (Id|ytr|yts) is also not in order means they can be reshuffled also..for ex
Id|ytr|dgfj|fhfjk|fgrt|yts
or they can be as ..
Id|wer|ytr|weg|yts
so I have done the following way and read them in java as shown below
String[] headers = firstLine.split("|");
int id, Ix, Ixt, count = 0;
for(String header : headers) {
if(header.equals("Id")) {
idIx = count;
}elseif (header.equals("Ix")) {
Ixt = count;
} elseif (header.equals("Ixt")) {
Ixt = count;
}
count++;
}
Now I need to store them in a map in such a way that against id I will get the value of column ytr and yts so in map there should be single key but against that key value could be multiple please advise how to store in map in such a way

Using a Map<Integer,List<String>> sounds like a viable first approach.
As it sound like your value is structured, it might be even better to create a value class to hold this, eg. Map<Integer, YourValueClass> where
class YourValueClass
{
String ix;
String ixt;
// constructor, getters and setters
}
Basically, you should think in terms of classes/objects - don't be in object denial :-)
Cheers,

I'm not quite sure what you mean, but if I get it right, you are looking for a multimap.
You can roll one yourself, as #Anders R. Bystrup suggests.
Or you can use an existing implementation like the Google Collections Multimap.

Don't store one key and multiple values. Instead, you can store a Key and Values as a List.

You can use MultiMap from Guava Library:
MultiMap<String,String> map = ArrayListMultimap.create();
map.put("key","value1");
map.put("key","value2");
By using:
System.out.println(map.get("key");
Prints:
["value1","value2"]

Value Class
class TextValues {
final int id;
final String ix;
final String ixt;
private TextValues(final int id, final String ix, final String ixt){
this.id = id;
this.ix = ix;
this.ixt = ixt;
}
public static TextValues createTextValues(int id, String ix, String ixt) {
return new TextValues(id, ix, ixt);
}
}
Usage:
Map<Integer, TextValues> map = new HashMap<Integer, TextValues>();
map.put(1, TextValues.createTextValues(1, "ix value ", "ixt value"));

public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> valSetOne = new ArrayList<String>();
valSetOne.add("ABC");
valSetOne.add("BCD");
valSetOne.add("DEF");
List<String> valSetTwo = new ArrayList<String>();
valSetTwo.add("CBA");
valSetTwo.add("DCB");
map.put("FirstKey", valSetOne);
map.put("SecondKey", valSetTwo);
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
String key = entry.getKey();
List<String> values = entry.getValue();
System.out.println("Value of " + key + " is " + values);
}
}
You can use Set or List based on your requirement i.e you need elements in ordered or unordered collection.This is a simple method of having single key with multiple values.

Related

Arraylist with two posting entries

I am new to collections. I need to know how I can use an ArrayList with two entries.
I am writing a program that reads a file and stores a string into a treemap and associating the string to an ArrayList with two columns(document id, count). I am wondering how I can do this. Can someone help me with some guidance on how I can do this? Here is how the system should be working:
For Eg:
If the program reads the word "Hello", the words need to be added to the treemap as Treemap("Hello", Arraylist).
The word Hello is associated with (DocumentID, Count) in an ArrayList.
In arraylist , we can't store in key value pair so instead of arrayList you can use pair.
Pair <String, Integer> pair = new Pair <String, Integer> ("DocumentId", count);
TreeMap("Hello", pair);
You can't put two values into an ArrayList. You could create a new class to store documentId and count. And then store this new Class in the List in the TreeMap:
public class CountPerDocument {
private final String documentId;
private final int count;
CountPerDocument(String documentId, int count){
this.documentId = documentId;
this.count = count;
}
public String getDocumentId() {
return documentId;
}
public int getCount() {
return count;
}
}
And fill your Map like this
Map<String, List<CountPerDocument>> map = new TreeMap<>();
List<CountPerDocument> list = new ArrayList<>();
//add code to fill your list here
list.add(new CountPerDocument("yourId", 23));
map.put("term", list);

How to get few random keys from HashMap

I have a map with titles. I want to print 10 random keys from my hashmap.
For example my map (String, Object) contains 100 pairs: "A, new Object(...)", "B, ...", "C, ..." etc.
I want to get 10 random keys from this map and append it to one string.
So my string should looks like: "A\nD\nB".
A quick way to get random 10 keys without repetition is putting the keys in a list and using Collections.shuffle to shuffle the list.
Map<String, Object> map = ...yourmap
ArrayList<String> keys = new ArrayList<>(map.keySet());
Collections.shuffle(keys);
List<String> randomTenKeys = keys.subList(0, 10);
Creating a list of all keys and shuffling it is not the most efficient thing you can do. You can do it in a single pass with a reservoir sampling algorithm. I haven't looked into it but you can probably find an implementation in some Apache or Guava library.
Joni's answer is quite good and short. But, here is a fully working example if you'd like. I split your problem into two methods - one to return a list of randomly selected keys and another to print keys in whichever way you like. You could combine the two methods into one. But, its better to keep them separate.
import java.util.*;
import java.util.stream.IntStream;
public class Test {
public static void main(String [] args){
Map<String, Object> map = new HashMap<>();
//You can use for loop instead to make a map of String, Integer.
IntStream.rangeClosed(0, 9).forEach(i -> map.put(i +"", i));//Map of 10 numbers.
List<String> keys = getRandomKeys(map, 3);
String allKeys = combineKeys(keys, "\n");
System.out.println(allKeys);
}
public static List<String> getRandomKeys(Map<String, Object> map, int keyCount) {
List<String> keys = new ArrayList<>(map.keySet());
for(int i = 0; i < map.size()-keyCount; i++){
int idx = (int) ( Math.random() * keys.size() );
keys.remove(idx);
}
return keys;
}
public static String combineKeys(List<String> keys, String separator){
String all = "";
for(int i = 0; i < keys.size() - 1; i++){
all = all + keys.get(i) + separator;
}
all += keys.get(keys.size()-1);//last element does not need separator.
return all;
}
}
HashMap Stores the values already in unsorted order it is random.
you can directly use
for(Map.Entry entry : map.entrySet())
str.append(entry.getKey()+" "+entry.getValue());
however if you want new order every time you can shuffle your data.
For Shuffle you need to get all keys in a array or list
Then you can shuffle that list and iterate over that list to get values from hashmap
This is a complementary answer to Joni's answer. Use String:join to join the randomTenKeys.
Given below is Joni's answer:
Map<String, Object> map = ...yourmap
ArrayList<String> keys = new ArrayList<>(map.keySet());
Collections.shuffle(keys);
List<String> randomTenKeys = keys.subList(0, 10);
and the complementary answer is:
String joinedKeys = String.join("\n", randomTenKeys);
Set<String> keys = myMap.keySet();
String combined = "";
for (int i=0; i<10; i++)
{
int random = (int)(Math.random() * keys.size());
String key = keys.get(random);
combined += key + "\n";
keys.remove(random);
}

Iterate over a HashMap with multiple values per key

I am currently learning sets and maps through university (still using Java 7).
They have given us a half finished to-do list app to complete. Currently the to-do list takes three String local variables to allow the user to state a job (aJob), a time to do it (aTime) and a date to do it (aDate).
The app also has an instance variable (today) that holds todays date.
I need to come up with a way to check the HashMap for any tasks that are due today. So I need to be able to query just the HashMap values attributed by the aDate local variable.
I know that to iterate Maps that I can place the keys or the values into a Set and then iterate over the set - not a problem. But if I use the values() method (within the Map class) to put these into a set - it places all three Strings per key into the set. I just want to move the aDate values into a set.
Any ideas?
I only seem to be able to find examples where the Maps have just a single Key and Single Value. This list has a single key and three values per key.
Any pointers would be good?
Kind Regards
Edit.....
Just thought I would add some code to help as there have been several different approaches - which I am all very greatful for. But not sure if they suit my needs....
The Job Class is constructed as such...
public Job(String aJob, String aDate, String aTime)
{
Job = aJob;
date = aDate;
time = aTime;
}
I then create the map within the instance declarations for the To Do List class....
Map<Integer, Job> toDoList = new HashMap<>();
So I need to know the best way to iterate over this map, but it is only the Job attribute 'aDate' that is possibly going to hold the value I am after.
Not sure if that helps at all?
Kind Regards
If really the only structure you're allowed to use is a Map where each key has 3 values (which is the case if I understand correctly), of which only one is a Date, you technically could do the following:
map.values()
.stream()
.filter(Date.class::isInstance)
...whatever else you want to do
The other suggested solutions are far better though, design wise.
If you can't use a custom class, as suggested by Toisen, maybe HashMap<String, HashMap<String, ArrayList<String>>> could do the trick for you.
I've added a sample of how to use it (as well as populating it with some random data)
public class FunkyMap {
private HashMap<String, HashMap<String, ArrayList<String>>> jobs;
// For random data
private String[] job = {"EAT", "SLEEP", "FART", "RELAX", "WORK"};
private String[] time = {"MORNING", "BEFORENOON", "NOON", "AFTERNOON", "EVENING", "MIDNIGHT"};
private String[] date = {"FIRST", "SECOND", "THIRD", "FOURTH"};
public FunkyMap() {
jobs = new HashMap<>();
// To populate some random data
Random r = new Random();
for(int i = 0; i < 20; i++) {
String d = date[r.nextInt(date.length)];
if(jobs.containsKey(d)) {
HashMap<String, ArrayList<String>> inner = jobs.get(d);
String t = time[r.nextInt(time.length)];
if(inner.containsKey(t)) {
inner.get(t).add(job[r.nextInt(job.length)]);
} else {
List<String> s = Arrays.asList(new String(job[r.nextInt(job.length)]));
inner.put(t, new ArrayList<String>(s));
}
} else {
jobs.put(d, new HashMap<String, ArrayList<String>>());
}
}
// Actual iteration over date => time => jobs
Iterator<String> i = jobs.keySet().iterator();
while(i.hasNext()) {
String iKey = i.next();
HashMap<String, ArrayList<String>> inner = jobs.get(iKey);
System.out.println("Jobs scheduled for " + iKey);
Iterator<String> j = inner.keySet().iterator();
while(j.hasNext()) {
String jKey = j.next();
ArrayList<String> actualJobs = inner.get(jKey);
System.out.println("\tAt " + jKey);
for(String s : actualJobs) {
System.out.println("\t\tDo " + s);
}
}
}
}
public static void main(String[] args) {
new FunkyMap();
}
}
I took the liberty to assume that dates were unique, and time was unique per date, while a time could hold any number of jobs including duplicates. If the last assumption with jobs is not true, you could swap ArrayList<String> with Set<String>.
Just create a class that holds all data that you need. E.g.
If you need something strange like Map<String, Tuple<String, Integer, Date>> just make a new class that holds the Tuple:
class TupleHolder {
private String firstValue;
private Integer secondValue;
private Date thirdValue;
// get/set here...
}
and use it: Map<String, TupleHolder>

Read objects content from hashmaps

I need to save pairs (string,object) into a hashmap. Basically I managed to populate the hashmap but I don't know how to access the values stored into memory.
This is my code:
HashMap<String, speedDial> SDs = new HashMap<String, speedDial>();
speedDial sd = new speedDial();
SDs.put(String.valueOf(temp),sd); whre temp is my index and sd my object
Then I fill in data into the sd reading them from an xml file.
When I debug the project with eclypse I can see the values are stored correctly into memory, but I've no idea how to retrive the string values associated to the object, see below the SD object format
class speedDial{
String label, dirN;
speedDial (String l, String dN) {
this.label = l;
this.dirN = dN;
}
}
See the picture below: it highlights the data I'm trying to access!
enter image description here
When I try to access the hashmap and print it's values I only got the last one, I use the following:
for ( int k = 0; k <50; k++) {
speedDial.printSD(SDs.get(String.valueOf(k)));
}
This is my printSD method taken from the speedDial class:
public static void printSD (speedDial SD) {
System.out.println("Dir.N: " + SD.dirN + " Label: " + SD.label);
}
And this is the output for all the 50 iterations, that is the last element I added to the hashmap in another for cycle that reads from a xml file.
Dir.N: 123450 Label: label5
Given a HashMap such as:
SpeedDial speedDial1 = new SpeedDial("test1", "test2");
SpeedDial speedDial2 = new SpeedDial("test3", "test4");
SpeedDial speedDial3 = new SpeedDial("test5", "test6");
HashMap<String, SpeedDial> exampleHashMap = new HashMap<>(3);
exampleHashMap.put("key1", speedDial1);
exampleHashMap.put("key2", speedDial2);
exampleHashMap.put("key3", speedDial3);
You can retrieve the value for a given key like so:
SpeedDial exampleOfGetValue = exampleHashMap.get("key1");
System.out.println(exampleOfGetValue.label);
System.out.println(exampleOfGetValue.dirN);
This outputs:
test1
test2
If you want to retrieve the keys for a given value then you could use something like:
public final <S, T> List<S> getKeysForValue(final HashMap<S, T> hashMap, final T value) {
return hashMap.entrySet()
.stream()
.filter(entry -> entry.getValue().equals(value))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
If you call this function like so:
List<String> exampleOfGetKeys = getKeysForValue(exampleHashMap, speedDial1);
System.out.println(exampleOfGetKeys);
It would output a list of all keys that have this value:
[key1]
The following code will iterate through the map and will store the key and values in two lists.
List<String> keys = new ArrayList();
List<Object> values = new ArrayList();
for (Map.Entry<String, Object> speedDial: SDs.entrySet()) {
Object speedDialValue = speedDial.getValue();
String key= speedDial.getKey();
keys.add(key);
values.add(speedDialValue);
}
To retrieve the String value, typically getters are used as it is recommended to use the private modifier for your class attributes.
public class speedDial{
private String label, dirN;
public speedDial (String l, String dN) {
this.label = l;
this.dirN = dN;
}
public String getLabel(){
return this.label;
}
public String getDirN(){
return this.dirN;
}
}
The you can simply use yourObject.getLabel(); or yourObject.getDirN();
Hope that helps!
SDs.keySet() Gives you the Set of the keys of your HashMap
You can have the list of values using
for (String mapKey : SDs.keySet()) {
System.out.println("key: "+mapKey+" value: "+ SDs.get(mapKey).toString());
}
Yous have to write a toString() fonction for your speedDial

How to modify ArrayList object if one of its field contain duplicate entries?

I have an ArrayList of type model class .Model class contain two fields
for Ex: number and name.
If the number is appearing multiple times then I need to append its corresponding name so that the number has to be a unique in ArrayList?
Lets say:
list.get(0).getNumber = 100,
list.get(0).getName = Narendra.
list.get(1).getNumber = 100,
list.get(1).getName = Modi.
list.get(2).getNumber = 101,
list.get(2).getName = xyz.
So my final list should contain only two items i.e.
list.get(0).getNumbet =100,
list.get(0).getName = Narendra Modi.
list.get(1).getNumbet =101,
list.get(1).getName = xyz.
It appears that what you really want is a multi-map. You can do this in plain Java 8 with
final Map<Integer, Set<String>> map = new HashMap<>();
public void put(Integer num, String name) {
map.computeIfAbsent(num, n -> new HashSet<>()).add(name);
}
put(100, "Narendra");
put(100, "Modi");
put(101, "xyz"):
With traditional java versions, you can use map as below:
Map<Integer, String> m = new HashMap<Integer, String>();
if(m.get(100) != null){
m.put(100,"Narendra");
}
else{
m.put(100, (m.get(100)+" Modi"));
}

Categories