I have a map that will be filled in a matter of time. problem is I want to know what the last added entry is. so far I only found the last entry in the map. is there a way to get the last added entry?
code so far:
int spawned = 0;
NavigableMap<String, Integer> minioncounter = new TreeMap<String, Integer>();
while (spawned < 7) {
if(!minioncounter.containsKey("big")){
minioncounter.put("big", 1);
}else if(!minioncounter.containsKey("small")){
minioncounter.put("small", 1);
}else if(minioncounter.containsKey("small") && minioncounter.get("small") < 2){
minioncounter.put("small", 2);
}else if(!minioncounter.containsKey("archer")){
minioncounter.put("archer", 1);
}else{
minioncounter.put("archer", minioncounter.get("archer")+1);
}
spawned++;
System.out.println(minioncounter.);
System.out.println(minioncounter);
}
Current console output:
{big=1}
{big=1, small=1}
{big=1, small=2}
{archer=1, big=1, small=2}
{archer=2, big=1, small=2}
{archer=3, big=1, small=2}
{archer=4, big=1, small=2}
the order in which it is already stated is the one I have to use later on.
See LinkedHashMap.
This Map implementation maintains keys in the order in which they were inserted (basically). That said, this may not meet your specific needs, I'd read the documentation.
It's simple enough to extend an existing implementation to provide even more control, though.
You can create your own StoreLastAddMap class that wraps the real NavigableMap. You expose the put method in your class where you will update the reference to the last added entry before calling the wrapped NavigableMap's add method.
public class StoreLastAddMap () {
NavigableMap<String, Integer> minioncounter = new TreeMap<String, Integer>();
private String lastAddedKey;
put(String key, Integer val) {
lastAddedKey = key;
minioncounter.put(key, val);
}
//getter for the wrapped Map to do other Map related stuff
NavigableMap getMap() {return minioncounter;}
Integer getLastAddedVal(){return minioncounter.get(lastAddedKey);}
String getLastAddedKey() {return lastAddedKey;}
}
Or something to that affect.
Related
Edit: Already solved using RDD.collectAsMap()
I am trying to replicate the solution to the problem from pages 28-30 of http://on-demand.gputechconf.com/gtc/2016/presentation/S6424-michela-taufer-apache-spark.pdf
I have a HashMap that I instantiate outside of the map function. The HashMap contains the following data:
{1:2, 2:3, 3:2, 4:2, 5:3}
A previously defined RDD previousRDD was has the type:
JavaPairRDD<Integer, Iterable<Tuple2<Integer, Integer>>>
has the data:
1: [(1,2), (1,5)]
2: [(2,1), (2,3), (2,5)]
3: [(3,2), (3,4)]
4: [(4,3), (4,5)]
5: [(5,1), (5,2), (5,4)]
I try to create a new RDD with a flatMapToPair:
JavaPairRDD<Integer, Integer> newRDD = previousRDD.flatMapToPair(new PairFlatMapFunction<Tuple2<Integer, Iterable<Tuple2<Integer, Integer>>>, Integer, Integer>() {
#Override
public Iterator<Tuple2<Integer, Integer>> call(Tuple2<Integer, Iterable<Tuple2<Integer, Integer>>> integerIterableTuple2) throws Exception {
Integer count;
ArrayList<Tuple2<Integer, Integer>> list = new ArrayList<>();
count = hashMap.get(integerIterableTuple2._1);
for (Tuple2<Integer, Integer> t : integerIterableTuple2._2) {
Integer tcount = hashMap.get(t._2);
if (count < tcount || (count.equals(tcount) && integerIterableTuple2._1 < t._2)) {
list.add(t);
}
}
return list.iterator();
}
});
But in this, the hashMap.get(t._2) inside the for loop gets NULLs most of the time. I have checked that the proper values are inside the HashMap.
Is there a way to properly get the values of a HashMap inside a Spark function?
It should work. Spark should capture your variable, serialize it and send to each worker with each task. You might try broadcasting this map
sc.broadcast(hashMap)
and use the result instead of hashMap. It is more efficient memory-wise too (shared storage per executor).
I had similar problem with class variables. You can try make your variable local or declare one more, like this:
Map localMap = hashMap;
JavaPairRDD<Integer, Integer> newRDD = previousRDD.flatMapToPair(
...
Integer tcount = localMap.get(t._2);
...
);
I think this is due to spark serialization mechanism. You can read more about it here.
The value of the hashtable is not decrmenting by 1 in second loop over maga_split array.They stays same as during the first loop.
Hashtable<String,Integer> notemap=new Hashtable<String,Integer>();
String[] note_split={give,one,grand,today};
String[] maga_split={give,me,one,grand,today,night};
for(int i=0;i<note_split.length;i++)
{
if(!notemap.contains(note_split[i]))
{
notemap.put(note_split[i],1);
}
else
{
notemap.put(note_split[i],notemap.get(note_split[i])+1);
}
}
for(int i=0;i<maga_split.length;i++)
{
String s=maga_split[i];
if(!notemap.contains(s))
{
notemap.put(s,1);
}
else
{
notemap.put(s,notemap.get(s)-1);
}
}
for(Map.Entry s:notemap.entrySet())
{
System.out.println(s.getKey()+"="+s.getValue()); }
Your code does not work because you are using notemap.contains(). If you read documentation for contains():
Tests if some key maps into the specified value in this hashtable. This operation is more expensive than the containsKey method. Note that this method is identical in functionality to containsValue, (which is part of the Map interface in the collections framework).
So you are not testing if key is in table, instead you are testing for value.
When using maps it is good idea to use Map interface where possible: Map<String, Integer> notemap = new HashMap<>();. This way you can be sure you are invoking standard interface for map, and you can switch implementation of map if needed, for example from HashMap to TreeMap.
Then you should use containsKey() method
The program is as below:
Hash<String, HashMap<String, HashMap<String, String>>> data = new Hash<String, HashMap<String, HashMap<String, String>>>();
HashMap<String, String> person = new HashMap<String, String>();
person.put("Name", json.getString("Name"));
person.put("Contact", json.getString("Contact"));
person.put("Email", json.getString("Email"));
person.put("Rent Start", json.getString("Rent Start"));
person.put("Rent End", json.getString("Rent End"));
String period = json.getString("Rent Start").substring(0, 7) + " To " + json.getString("Rent End").substring(0, 7);
data.get(roomType).put(period, person);
Assume "data" is not empty in each level.
Problem occurs in the following step.
data.get(roomType).put(period, person);
When I do so, all values in the hashmap that in the second level become the person hashmap.
For example, in "roomtype1", there are 2 period, "2015-07 To 2016-07"
and "2015-07 To 2017-07".
When I run this code:
data.get(roomtype1).put("2015-07 To 2016-07", person);
the hashmap got by
data.get(roomtype1).get("2015-07 To 2017-07");
also becomes person.
May I know why?
(p.s. The original hashmap has 5 levels. I reduced it for this post because it will be easier to be understood)
Java objects are reference type.
data.get(key1) will get the hashmap object in the second level. with that object you are adding one more object into it.
When I do so, all values in the hashmap that in the second level
become the addition hashmap.
What does data.get(roomType) ? Is it doing something like:
public V get(K key) {
V actual = super.get(key);
if (null == actual) {
actual = getANewV();
super.put(key, actual);
}
return actual;
}
And are you sure that the getANewV() always returns a new instance and not the same (which would explains all values in the hashmap that in the second level become the addition hashmap).
And your need already exists in the matter of Multimap (see Guava). You should probably see if that work for you.
Beside, I'd personally use object rather than multiple layer of maps.
I have two maps:
Map<Date, List<Journey>> journeyMap = new TreeMap<Date, List<Journey>>
Map<Date, List<Job>> jobMap = new TreeMap<Date, List<Job>>
I used TreeMap because that means they're sorted by date but I want to go through both maps at the same time, get the values of Journey/Job, then do some work.
I think i could use generics, storing the Job/Journey as an Object, then checking the instanceOf but I'm not sure if thats the solution?
Thanks.
Even though the others are right, that there are better, safer and more comfortable ways to achive whatever you want, it is possible to iterate over (the entries of) two Maps (aka Collections) at the same time.
//replace keySet() with your favorite method in for-each-loops
Iterator<Date> journeyIterator = journeyMap.keySet().iterator()
Iterator<Date> jobIterator = jobMap.keySet().iterator();
while(journeyIterator.hasNext() && jobIterator.hasNext()){
Date journeyDate = journeyIter.next()
Date jobDate = jobIterator.next();
//... do whatever you want with the data
}
This code does explicitly, what a for-each-loop can do implicitly for one Collection. It retrieves the Iterator and gets the element from the Collection from it, much like reading a file.
You're making an assumption that these maps are having values sorted in the very same way, but this is definitely not correct. At least if you want to write a logic like this you need to declare the same implementing class as a reference:
TreeMap<Date, List<Journey>> journeyMap = new TreeMap<Date, List<Journey>>
TreeMap<Date, List<Job>> jobMap = new TreeMap<Date, List<Job>>
but believe me you don't want to do it.
You're right! Instead doing 2 maps create 1, holding pair of Job/Journey objects - create a JobJourneyHolder class which holds both objects, this will be a good solution.
Yes, defining a new class for that is definitely the solution, because it composes related objects together, which is very welcomed in OOP. And you should not forget to implement hashCode() and equals() methods to make such classes work properly in Java collections:
public final class JourneyJob {
final Journey journey;
final Job job;
public JourneyJob(Journey journey, Job job) {
if (journey == null || job == null)
throw new NullPointerException();
this.journey = journey;
this.job = job;
}
public int hashCode() {
return Objects.hash(journey, job);
}
public boolean equals(JourneyJob other) {
return other.job.equals(job) && other.journey.equals(journey);
}
}
To add elements to common Map:
Map<Date, List<JourneyJob>> map = new TreeMap<>();
...
if (map.contains(date)) {
map.get(date).add(new JourneyJob(journey, job));
} else {
map.put(date, new ArrayList<>(Arrays.asList(new JourneyJob(journey, job)));
}
...
To retrieve JourneyJob objects:
for (List<JourneyJob> jjList : map.values()) {
for (JourneyJob jj : jjList) {
journey = jj.journey;
job = jj.job;
//... do your work here
}
}
Or, if you use Java 8, this can be done using nested forEach():
map.values().stream().forEach(list ->
list.stream().forEach(jj -> {
Journey journey = jj.journey;
Job job = jj.job;
//... do your work here
})
);
This question already has answers here:
Java Hashmap: How to get key from value?
(39 answers)
Closed 5 years ago.
I want to get the key of a HashMap using the value.
hashmap = new HashMap<String, Object>();
haspmap.put("one", 100);
haspmap.put("two", 200);
Which means i want a function that will take the value 100 and will return the string one.
It seems that there are a lot of questions here asking the same thing but they don't work for me.
Maybe because i am new with java.
How to do it?
The put method in HashMap is defined like this:
Object put(Object key, Object value)
key is the first parameter, so in your put, "one" is the key. You can't easily look up by value in a HashMap, if you really want to do that, it would be a linear search done by calling entrySet(), like this:
for (Map.Entry<Object, Object> e : hashmap.entrySet()) {
Object key = e.getKey();
Object value = e.getValue();
}
However, that's O(n) and kind of defeats the purpose of using a HashMap unless you only need to do it rarely. If you really want to be able to look up by key or value frequently, core Java doesn't have anything for you, but something like BiMap from the Google Collections is what you want.
We can get KEY from VALUE. Below is a sample code_
public class Main {
public static void main(String[] args) {
Map map = new HashMap();
map.put("key_1","one");
map.put("key_2","two");
map.put("key_3","three");
map.put("key_4","four");
System.out.println(getKeyFromValue(map,"four"));
}
public static Object getKeyFromValue(Map hm, Object value) {
for (Object o : hm.keySet()) {
if (hm.get(o).equals(value)) {
return o;
}
}
return null;
}
}
I hope this will help everyone.
If you need only that, simply use put(100, "one"). Note that the key is the first argument, and the value is the 2nd.
If you need to be able to get by both the key and the value, use BiMap (from guava)
You have it reversed. The 100 should be the first parameter (it's the key) and the "one" should be the second parameter (it's the value).
Read the javadoc for HashMap and that might help you: HashMap
To get the value, use hashmap.get(100).
You mixed the keys and the values.
Hashmap <Integer,String> hashmap = new HashMap<Integer, String>();
hashmap.put(100, "one");
hashmap.put(200, "two");
Afterwards a
hashmap.get(100);
will give you "one"
if you what to obtain "ONE" by giving in 100 then
initialize hash map by
hashmap = new HashMap<Object,String>();
haspmap.put(100,"one");
and retrieve value by
hashMap.get(100)
hope that helps.
public class Class1 {
private String extref="MY";
public String getExtref() {
return extref;
}
public String setExtref(String extref) {
return this.extref = extref;
}
public static void main(String[] args) {
Class1 obj=new Class1();
String value=obj.setExtref("AFF");
int returnedValue=getMethod(value);
System.out.println(returnedValue);
}
/**
* #param value
* #return
*/
private static int getMethod(String value) {
HashMap<Integer, String> hashmap1 = new HashMap<Integer, String>();
hashmap1.put(1,"MY");
hashmap1.put(2,"AFF");
if (hashmap1.containsValue(value))
{
for (Map.Entry<Integer,String> e : hashmap1.entrySet()) {
Integer key = e.getKey();
Object value2 = e.getValue();
if ((value2.toString()).equalsIgnoreCase(value))
{
return key;
}
}
}
return 0;
}
}
If you are not bound to use Hashmap, I would advise to use pair< T,T >.
The individual elements can be accessed by first and second calls.
Have a look at this http://www.cplusplus.com/reference/utility/pair/
I used it here : http://codeforces.com/contest/507/submission/9531943