Same key - Different Value with a HashMap - java

I'll start with what I want to achieve
Intention
The software parses XML-Data in a for-loop. The for-loop which handles the data will go until 50 (because I'm getting 50 different results). What I did at first was, that the doInBackground-method parses the whole XML data and saves it into TextViews and displays it. But now I wanted to add a splash-screen that gets displayed as long the data loads.
The XML-File is built up like any other normal XML-file, so when I go through a for-loop the keys are always the same, but the values differ.
Approaches
What I already did was to create an multidimensional array, but unfortunately you can't use Strings as an index. That's what the Map is for. This was my approach
stringArray[i]["source"] = sourceString;
Well, then I tried it with a Map. But the problem with the map was, that when the new key came again, it would just overwrite the previous key-value pair.
So I figured out I would use a HashMap with a String Collection. I handled it like this;
First I created the HashMap
public HashMap <String, Collection<String>> hashMap = new HashMap<String, Collection<String>>();
Then I put data in the HashMap for each key.
hashMap.put("source" , new ArrayList<String>());
This is what I have done in the for-loop
hashMap.get("source").add(new String(((Node) sourceList.item(0)).getNodeValue()));
Then, when finished, the onPostExecute-method starts a new intent and passes the hashMap.
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Intent i = new Intent(SplashScreen.this, MainActivity.class);
i.putExtra("hashMap", hashMap);
startActivity(i);
finish();
}
And in my MainActivity I'm doing this to get the data
Intent intent = getIntent();
HashMap<String, String> hashMap = (HashMap<String, String>)intent.getSerializableExtra("hashMap");
rankingDate = new TextView(this);
rankingDate.setText("RankingDate: " + hashMap.get("rankingDate"));
layout.addView(rankingDate);
But this results in a ClassCastException : `ArrayList cannot be cast to java.lang.String" in this line
source.setText("source: " + hashMap.get("source"));
I guess it's because hashMap.get("source") contains all values of the source data. So I tried to save all the data in a String Array. But this didn't work, but I don't know why. Eclipse tells me that Type mismatch: cannot convert from String to String[]
Any advice? I'm dying to solve this problem.

You got a typo:
HashMap<String, String> hashMap = (HashMap<String, String>)intent.getSerializableExtra("hashMap");
should be:
HashMap<String, Collection<String>> hashMap = (HashMap<String, Collection<String>>)intent.getSerializableExtra("hashMap");

#Eng.Fouad answer is correct, you have an error in the casting.
You might consider using a MultiMap rather than a map of collections:
http://guava-libraries.googlecode.com/svn/tags/release03/javadoc/com/google/common/collect/Multimap.html

Use a list of maps.
You can call list.get(index).get("source") and get the result later.
semi pseudocode:
List<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>
foreach(entry in document)
map = new HashMap<String,String>();
foreach(xml in entry)
map.put(xml,xml.value)
end
list.put(index++,map)
end

Your casting your hashmap incorrectly in your main activity.
Try this:
HashMap<String, Collection<String>> hashMap = (HashMap<String, Collection<String>>)intent.getSerializableExtra("hashMap");
Hope this helps :)

Related

Make a registry/database list in Java

I wonder how to make a registry/database list in Java. I mean if I, for example, have a variable called "data", and then I add a new entry to that called "name" with the value "David". Then I would call something like "data.name" to get the value "David".
As seen on this picture
I've been Googling but not finding anything about it.
It sounds like you want a Map from String to String. You can use a HashMap<String,String> for that.
// Create Map using HashMap
Map<String, String> data = new HashMap<String, String>();
// Set name
data.put("name", "David");
// Get name
String name = data.get("name");
System.out.println(name);

Trouble with displaying hashmap

My App: has two activities, one to create two strings (name and message), which are saved into a hashmap, transferred into JSON and saved in a SharedPreference.
The other activity fetches this SharedPreference, transfers it into a hashmap again. Then the map is "read out" by an Iterator.
Supposed to be: My Idea is, that if I do this process several times, the iterator "reads out" all the entries to the hashmap.
Problem: However, only the last input gets displayed.
Question: Why is only the last input displayed? Am I overriding the hashmap or parts of it? And if so, how can I avoid it? Or what else am I doing wrong?
Activity 1:
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put(message, name);
Gson gson = new Gson();
String hashMapString = gson.toJson(map);
SharedPreferences prefs = getSharedPreferences("SP", MODE_PRIVATE);
prefs.edit().putString("hashString", hashMapString).apply();
Activity 2:
Gson gson = new Gson();
SharedPreferences prefs = getSharedPreferences("SP", MODE_PRIVATE);
String storedHashMapString = prefs.getString("hashString", "Error");
java.lang.reflect.Type type = new TypeToken<LinkedHashMap<String, String>>(){}.getType();
LinkedHashMap<String, String> map = gson.fromJson(storedHashMapString, type);
Iterator myIterator = map.keySet().iterator();
while(myIterator.hasNext()) {
String key=(String)myIterator.next();
String value=(String)map.get(key);
Toast.makeText(getApplicationContext(), "Key: "+key+" Value: "+value, Toast.LENGTH_LONG).show();
}
while doing this
prefs.edit().putString("hashString", hashMapString).apply();
you are just saving values of newly created hashmap but old losing values which were saved previously using hashString key
Solution: fetch the old value and save it along with new values
Option one : fetch previous string , convert it to jsonobject then add the values to map
Reference : creating Hashmap from a JSON String
Option two : if you have only string key-value pair then
remove { and } from both new and old map strings then simply combine them and add { and } boundary symbols
String allValues ="{"+((prefs.getString("hashString", "")+hashMapString)
.replace("{","").replace("}",""))+"}";
then later save it
prefs.edit().putString("hashString", allValues).apply();
you are seeing the last input because putString overwrites whatever was there in the first place
https://developer.android.com/reference/android/content/SharedPreferences.Editor.html

understand Hash map keys- java

I know that HashMap doesn’t allow duplicate keys (It does allow duplicate values).
However in this example that works perfectly,all the values have the same key(that means the key is not unique)Maybe I misunderstood the code.Could someone help me understand it right.
this is the code
public class PlayListManager {
//**********************************hashmap keys************************
public static final String ALL_VIDEOS = "AllVideos";
public static final String ALL_Songs = "AllSongs";
//***************************************************************************
..
...
....
while (cursor.moveToNext()) {
Songs song = new Songs();
song.songId = cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
song.artist = cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
song.title = cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
song.songName = cursor
.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
song.duration = Integer.parseInt(cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)));
song.albumId = Integer.parseInt(cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID)));
song.songData = cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
//*******here it uses the same ky for all the videos?!!*************
HashMap<String, Object> songMap = new HashMap<String, Object>();
songMap.put(ALL_Songs, song);
songsList.add(songMap);
}
}
In each iteration of the while loop, the code is creating a new HashMap instance and filling it with only one entry that maps a String key ("AllSongs") to the Song object.
This map (which contains only one entry) will then be added to the list songsList.
After the while loop is finished, you would have a list of HashMaps where each map basically maps a hardcoded keyword to one song.
songsList:
<"AllSongs", song1>, <"AllSongs", song2>, <"AllSongs", song3>, ...
In this case, using a HashMap seems redundant. You could just fill the list with the Song instances without saving each one in a map.
The key concept here is that there are many HashMap (each iteration creates one), as opposed to having a "global" HashMap. If it were global, each song would overwrite the other since they are always mapped using the same hardcoded key.

Android Shared Prefs Map key-values to ArrayList to ListView row - UPDATED

Here's what I'm trying to do:
- Retrieve a Map of key-value pairs from a SharedPreferences object (User#, Name)
- write those key-value pairs into an ArrayList such that I can
- use them to populate a ListView with each row containing BOTH the key and the value like so:
User 1 - Joe R.
User 2 - Frank B.
etc
UPDATE:
so after taking a good long look at the SimpleAdapter class, and talking with some wiser more knowledgable folks - I'm a lot closer than I was... but still not all the way there.
here's what I have now:
public class LogHistory extends ListActivity {
static final ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
private static final String KEY = null;
private static final String VALUE = null;
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.log_history);
SharedPreferences logPrefs = getSharedPreferences(LoginField.PREFSNAME, 0);
Map<String, ?> logMap = logPrefs.getAll();
for (Map.Entry<String, ?> e : logMap.entrySet()) {
HashMap<String, String> row = new HashMap<String, String>();
String mKey = e.getKey();
String mValue = (String) e.getValue();
row.put(KEY, mKey);
row.put(VALUE, mValue);
list.add(row);
// FOR DEBUGGING PURPOSES
makeToast(mKey);
makeToast(mValue);
}
SimpleAdapter adapter = new SimpleAdapter(
this,
list,
R.layout.list_item,
new String[] { KEY, VALUE },
new int[] {R.id.item1, R.id.item2}
);
setListAdapter(adapter);
This sort of works - but only half way... what I get as a result is a list of the VALUES in both columns...
HOWEVER the makeToast function returns the proper values for both the KEY and the VALUE - so the problem must be in the SimpleAdapter method yes??
assistance would be great - homework is due tonight! :-0
You need to search for "custom listview", "listview custom adapter" and those things. "two line listview item layout"...
See this example. There are others on Google.
Basically, you can create a ArrayList<Hashmap<String,String>>, which is your data container. You add values to that creating as many HashMap<String, String> objects as you need and using list.add(yourHashMap), where list is the ArrayList.
At the end you feed that to a SimpleAdapter (there are other methods, but this works without much trouble).
Check the docs to see how each thing works exactly.
You are nulling your index keys. Put a name into those final Strings.
This sort of works - but only half way... what I get as a result is a list of the VALUES in both columns...
HOWEVER the makeToast function returns the proper values for both the KEY and the VALUE - so the problem must be in the SimpleAdapter method yes??
As I said, no. When you do this:
row.put(KEY, mKey);
row.put(VALUE, mValue);
You are not providing a meaninful difference between KEY and VALUE, because both are null. It's something like putting all things into the same column.
Your mistake into reasoning that is because the Toast test you created yourself test only the correctness of the values, not the columns:
makeToast(mKey);
makeToast(mValue);
In that you test only the values. ;) You assume that the columns are right, and that the mistake could only be in the values, which is exactly the opposite.
First rule of dealing with computers: computers never assume LOL. ;-)

adding a key to HashMap without the value?

Is there a way to add a key to a HashMap without also adding a value? I know it seems strange, but I have a HashMap<String, ArrayList<Object>> amd I want to first be able to create keys as needed and then check if a certain key exists and, if so, put the appropriate value, namely the ArrayList<Object>
Was that confusing enough?
Since you're using a Map<String, List<Object>>, you're really looking for a multimap. I highly recommend using a third-party library such as Google Guava for this - see Guava's Multimaps.
Multimap<String, Object> myMultimap = ArrayListMultimap.create();
// fill it
myMultimap.put("hello", "hola");
myMultimap.put("hello", "buongiorno");
myMultimap.put("hello", "สวัสดี");
// retrieve
List<String> greetings = myMultimap.get("hello");
// ["hola", "buongiorno", "สวัสดี"]
Java 8 update: I'm no longer convinced that every Map<K, SomeCollection<V>> should be rewritten as a multimap. These days it's quite easy to get what you need without Guava, thanks to Map#computeIfAbsent().
Map<String, List<Object>> myMap = new HashMap<>();
// fill it
myMap.computeIfAbsent("hello", ignored -> new ArrayList<>())
.addAll(Arrays.asList("hola", "buongiorno", "สวัสดี");
// retrieve
List<String> greetings = myMap.get("hello");
// ["hola", "buongiorno", "สวัสดี"]
I'm not sure you want to do this. You can store null as a value for a key, but if you do how will be able to tell, when you do a .get("key") whether the key exists or if it does exist but with a null value? Anyway, see the docs.
You can put null values. It is allowed by HashMap
You can also use a Set initially, and check it for the key, and then fill the map.
Yes, it was confusing enough ;) I don't get why you want to store keys without values instead just putting empty arraylists instead of null.
Adding null may be a problem, because if you call
map.get("somekey");
and receive a null, then you do not know, if the key is not found or if it is present but maps to null...
//This program should answer your questions
import java.util.*;
public class attemptAddingtoHashMap { //Start of program
//MAIN METHOD #################################################
public static void main(String args[]) { //main begins
Map<String, ArrayList<Object>> hmTrial = new HashMap<String, ArrayList<Object>>();
ArrayList alTrial = new ArrayList();//No values now
if (hmTrial.containsKey("first")) {
hmTrial.put("first", alTrial); }
else {hmTrial.put("first",alTrial);}
//in either case, alTrial, an ArrayList was mapped to the string "first"
//if you choose to, you can also add objects to alTrial later
System.out.println("hmTrial is " + hmTrial); //empty now
alTrial.add("h");
alTrial.add("e");
alTrial.add("l");
alTrial.add("l");
alTrial.add("o");
System.out.println("hmTrial is " + hmTrial);//populated now
} //end of main
//#############################################################################################################
} //end of class
//Note - removing objects from alTrial will remove the from the hashmap
//You can copy, paste and run this code on https://ide.geeksforgeeks.org/

Categories