How would I refactor the code below into 1 generic method?
(background info, it is used to get values from a Json string used with GSON library)
ArrayList<Map<Object, Object>> theme = new ArrayList<Map<Object, Object>>();
for (int i = 0; i < obj.getThemeList().size(); i = i + 1) {
if(Boolean.parseBoolean(obj.getThemeList().get(i).getChecked())){
Map<Object,Object> map = new HashMap<Object,Object>();
map.put("id", obj.getThemeList().get(i).getId());
map.put("name", obj.getThemeList().get(i).getName());
theme.add(map);
}
}
ArrayList<Map<Object, Object>> tag = new ArrayList<Map<Object, Object>>();
for (int i = 0; i < obj.getTagList().size(); i = i + 1) {
if(Boolean.parseBoolean(obj.getTagList().get(i).getChecked())){
Map<Object,Object> map = new HashMap<Object,Object>();
map.put("id", obj.getTagList().get(i).getId());
map.put("name", obj.getTagList().get(i).getName());
tag.add(map);
}
}
Basically, just make it a single method that accepts the getThemeList() or getTagList(), no? It looks like that's the only difference between them...
I think you mean "how can I refactor this to reuse code", because generics does not apply here as much as refactoring does.
Firstly, read up on the foreach syntax - your for loop is really ugly.
You haven't given much to go on, but try this:
public interface HasIdNameAndChecked {
String getChecked();
String getId();
String getName();
}
public static List<Map<String, String>> extractList(List<? extends HasIdNameAndChecked> items) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
for (HasIdNameAndChecked item : items) {
if (Boolean.parseBoolean(item.getChecked())){
Map<String, String> map = new HashMap<String, String>();
map.put("id", item.getId());
map.put("name", item.getName());
list.add(map);
}
}
return list;
}
Then have your Theme and Tag classes implement HasIdNameAndChecked, and call it like this:
List<Map<String, String>> list1 = extractThemeList(obj.getThemeList());
List<Map<String, String>> list2 = extractThemeList(obj.getTagList());
Disclaimer: I typed this in without an IDE, so there could be a couple of typos.
Well, let's do it in following order:
Identify what varies. themeList and tagList.
Identify common properties and behaviour. getChecked(), getId(), getName().
Apply generalization for what varies. Define a common interface for what varies: abstract class, interface, behaviour, etc.
Update your solution to generalized solution.
Related
My java code is this:
List<SysUser> sysUserDeleteDuplicate = new ArrayList<SysUser>(new HashSet<SysUser>(sysUser));
List<Map<String, Object>> rList = new ArrayList<Map<String, Object>>();
if(sysUserDeleteDuplicate!=null && sysUserDeleteDuplicate.size()>0){
for (int i=0; i<sysUserDeleteDuplicate.size(); i++){
Map<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("text", sysUserDeleteDuplicate.get(i).getRealname());
resultMap.put("value", sysUserDeleteDuplicate.get(i).getId());
rList.add(resultMap);
}
}
I want to sort elements in rList by String ascending.
And the data in rList likes this:
[{text=peter,value=1001},{text=lucy,value=1004},{text=kate,value=1002}]
I want this result:
[{text=kate,value=1002},{text=lucy,value=1004},{text=peter,value=1001}]
As each list element is a Map potentially containing more than one instance of Object, you first need to re-define your sort criteria.
It would work if you say that you want to sort the list by the greatest Object in the Map.
But as java.lang.Object does not define java.lang.Comparable<Object>, there is no natural order for instances of Object. So you need to define a sorting criteria for Object, too. As there are not that many attributes, only the hash code or the result of Object.toString() would work.
With these informations, you can implement a Comparator that can be used as argument to List.sort().
You'll need to make a custom comparator (some sorting criteria) for this. Something like:
Collections.sort(rListMap, new Comparator<Map<String, Comparable>> () {
#Override
public int compare(Map<String, Comparable> a1, Map<String, Comparable> a2) {
return a2.get(someThing).compareTo(a1.get(someThing));
}
});
As Shubham and tquadrat said,I modified List<Map<String, Object>> to
List<Map<String, String>>
I use this code:
List<SysUser> sysUserDeleteDuplicate = new ArrayList<SysUser>(new HashSet<SysUser>(sysUser));
List<Map<String, String>> rList = new ArrayList<Map<String, String>>();
if(sysUserDeleteDuplicate!=null && sysUserDeleteDuplicate.size()>0){
for (int i=0; i<sysUserDeleteDuplicate.size(); i++){
Map<String, String> resultMap = new HashMap<String, String>();
resultMap.put("text", sysUserDeleteDuplicate.get(i).getRealname());
resultMap.put("value", sysUserDeleteDuplicate.get(i).getId());
rList.add(resultMap);
}
}
Collections.sort(rList, new Comparator<Map<String, String>> () {
#Override
public int compare(Map<String, String> a1, Map<String, String> a2) {
return a1.get("text").compareTo(a2.get("text"));
}
});
System.out.println(rList.toString());
output:
[{text=kate, value=1002}, {text=lucy, value=1004}, {text=peter, value=1001}]
I have an ArrayList HashMap like the one below.
ArrayList<HashMap<String, String>> mArrType = new ArrayList<>();
with the following values added into it
HashMap<String, String> map;
map = new HashMap<String, String>();
map.put("type", "TRIMMER");
map.put("request", "5");
map.put("actual", "0");
mArrType.add(map);
map = new HashMap<String, String>();
map.put("type", "HAND ROUTER");
map.put("request", "6");
map.put("actual", "0");
mArrType.add(map);
map = new HashMap<String, String>();
map.put("type", "AIR COMPRESSOR");
map.put("request", "6");
map.put("actual", "0");
mArrType.add(map);
Question is how can i get the position of a hashmap from arraylist. eg : hashmap with 'type' trimmer has a position 0 in arraylist, I want to retrieve the position value "0"
I'll write a small util method
private static int getTrimmerTypeMapPosition(ArrayList<HashMap<String, String>> mArrType) {
for (int i = 0; i < mArrType.size(); i++) {
HashMap<String, String> mp = mArrType.get(i);
if (mp.get("type").equals("TRIMMER")) {
return i;
}
}
return -1;
}
To make this method very generic, have "type" and "TRIMMER" as method params, so that you can just pass any key and value pairs to check with.
That's not efficiently possible with your data structure. You can either store the own position in each HashMap or loop through all entries and search for the one with the type you are looking for.
You can, of course, define another HashMap<String, Integer> which maps all your type strings to the corresponding ArrayList index.
Others answer is also correct, but you can do this thing using Java8 also.
E.g.:
int index = IntStream.range(0, mArrType.size()).
filter(i -> mArrType.get(i).get("type").equals("TRIMMER"))
.findFirst().getAsInt();
I'm getting the error
error: incompatible types: String cannot be converted to ArrayList<String>
crazyMap.put(company, day);
when I run this code
Map<String, ArrayList<String>> crazyMap = new HashMap<String, ArrayList<String>>();
String company = "myCompany";
String day = "Monday";
crazyMap.put(company, day);
How can I go about formatting the 'day' parameter to satisfy the type error?
What is your goal with the data structure?
Should crazyMap store a company that maps to a single day like you are trying to add above? If so, try:
Map<String, String> crazyMap = new HashMap<String, String>();
String company = "myCompany";
String day = "Monday";
crazyMap.put(company, day);
Or do you want crazyMap to have a company that maps to multiple days? Something like this:
Map<String, Collection<String>> crazyMap = new HashMap<String, Collection<String>>();
Collection<String> days = new ArrayList<String>();
days.add("Monday");
crazyMap.put("myCompany", days);
Instead of bothering with the ArrayList yourself, I would recommend to use an already existing type with designed for multiple values: Guavas Multimap (explanation; JavaDoc).
Instead of doing this:
Map<String, ArrayList<String>> crazyMap = new HashMap<>();
crazyMap.put("myCompany", new ArrayList<>(Arrays.asList("Monday")));
You can do this:
Multimap<String, String> crazyMap = ArrayListMultimap.create();
crazyMap.put("myCompany", "Monday");
This also avoids ugly stuff like:
ArrayList<String> items;
if (crazyMap.containsKey("myCompany")) {
items = crazyMap.get("myCompany");
} else {
items = new ArrayList<>();
}
items.add("Tuesday");
crazyMap.put("myCompany", items);
Guava cares about creating the collection for you, if it doesn't exist. Just call:
crazyMap.put("myCompany", "Tuesday");
and everything is done.
One disadvantage is, that the used interface is MultiMap which doesn't extend Map. This means you have to "weaken" the variable type to MultiMap, like:
public void someMethod(MultiMap<K, V> multimap)
instead of:
public void someMethod(Map<K, Collection<V>> multiMap)
Read more about the differences here: "Multimap Is Not A Map".
You can find the newest version of Guava on the maven repository.
I have this ArrayList
public ArrayList<HashMap<String, String>> xmlFileNames = new ArrayList<>();
and I want to convert this to:
HashMap<String, String> comparemap2 = new HashMap<>();
What I want is: I want all the Items inside the ArrayList and want to put them into the HashMap
My HashMap looks like:
KEY VALUE
job_id 032014091029309130921.xml
job_id 201302149014021492929.xml
job_id 203921904901920952099.xml
EDIT:
Later I want to compare this map with an existing map:
Properties properties = new Properties();
try {
properties.load(openFileInput("comparexml.kx_todo"));
} catch (IOException e) {
e.printStackTrace();
}
for (String key : properties.stringPropertyNames()) {
compareMap.put(key, properties.get(key).toString());
}
HashMap<String, String> oldCompareMap = new HashMap<>();
for (HashMap key : xmlFileNames) {
oldCompareMap.putAll(key);
}
isEqualMaps(oldCompareMap, compareMap);
I only want to compare, if the filename exists in the compareMap. If not, than add it to the xmlFileName Map
I've looked up in StackOverFlow, how I can convert ArrayList to HashMap. But the other Threads treat data types like Item or Product.
I hope you can help me!
Kind Regards
Given...
public ArrayList<HashMap<String, String>> xmlFileNames = new ArrayList<>();
then something like this should do it.
HashMap<String, String> nhm = new HashMap<>();
for (HashMap xmlFileHm : xmlFileNames ) {
nhm.putAll(xmlFileHm);
}
but be aware if you have duplicate keys in your hashmaps they will get overwritten.
You should also think about coding to interfaces. Take a look at Map and List rather than typing your collections to implementations (ArrayList and HashMap). Take a look at this thread which is quite interesting What does it mean to "program to an interface"?
Depending on what you are trying to do as well you might consider a MultiMap as this might server your purposes better
Edit After update to the question...
A multimap would be better here with one key and multiple values. Although arguably if the key never changes then you could just store the values in a list. For multiamps you can use Google's guava library or do one yourself. For example (not checked for compilation errors as Im doing this from my head)
Map<String, List<String>> m = new HashMap<>();
if (m.containsKey("key")) {
m.get("key").add("new value");
}
else {
List<String> l = new ArrayList<>();
l.add("new value");
m.put("key", l);
}
You can create a new HashMap, then iterate through the list and put all elements from the map from the list to the main map.
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> map = new HashMap<>();
for (Map<String, String> mapFromList : list) {
map.putAll(mapFromList);
}
You can try something like this..
ArrayList<HashMap<String, String>> xmlFileNames = new ArrayList<>();
HashMap<String, String> comparemap2 = new HashMap<>();
for(HashMap<String, String> i:xmlFileNames){
comparemap2.putAll(i);
}
You may need to consider the case of duplicate keys. else they will get override.
Create a new map and put All each element of arrayList to the map.
But in that case if you have same keys in two element of arrayList (hashmap) then it will override the previous one.
I have got some troubles converting each value in my HashMap to a String.
private static HashMap<String, List<Music>> musiksammlung = new
HashMap<String, List<Music>>();
This is my constructor for the HashMap. The key represents the album, the value a list of tracks from this album.
Now I want to convert each Music object to a String without creating a new HashMap, is this
possible?
I've tried it with the Iterator scheme, for loop over the entry set and so on but nothing seems to work.
Edit://
My code for the convertmethod:
public HashMap<String, List<String>> generateFormatList() {
HashMap<String, List<String>> formatList = new HashMap<String, List<String>>();
for(String key : musiksammlung.keySet())
formatList.put(key, musiksammlung.get(key).toString());
return musiksammlung;
}
But this always results in an error "is not applicable for the Arguments (String, String) so I have no idea. Do I have to override toString()?
You're on the right path but you need to convert the existing List<Music> to a List<String> and put the List<String> into your new HashMap.
You also then want to return your newly created HashMap<String, List<String>> instead of your original one.
public HashMap<String, List<String>> generateFormatList() {
HashMap<String, List<String>> formatList = new HashMap<String, List<String>>();
for(String key : musiksammlung.keySet()) {
// Value to store in map
List<String> value = new ArrayList<String>();
// Get the List<Music>
List<Music> musicList = musiksammlung.get(key);
for (Music m: musicList) {
// Add String of each Music object to the List
value.add(m.toString);
}
// Add the value to your new map
formatList.put(key, value);
}
// Return the new map
return formatList;
}
So answer your question:
Now I want to convert each Music object to a String without creating a
new HashMap, is this possible?
You need to create a new HashMap, because it's storing different type of value: List<Music> is different from List<String>.
Also as mentioned in my previous answer, make sure you override Music.toString() so that it returns a meaningful String for you instead of the one it inherits from its parent classes, which includes at least java.lang.Object
formatList wants a List<String>, but musiksammlung.get(key).toString() returns a String (not a List<String>). Did you mean this?
HashMap<String, String> formatList = new HashMap<String, String>();
Have you tried something like this:
Iterator<String> it = musiksammlung.keySet().iterator();
while (it.hasNext()) {
List<Music> ml = musiksammlung.get(it.next());
for (Music m : ml)
System.out.println(m.toString());
}
And of course you should override the Music#toString() method with something you could use.
Try to change your HashMap like this:
private static HashMap<String, List<Object>> musiksammlung = new HashMap<String,List<Object>>();
So you can save any kind of objects in this HashMap. Also use instanceof to check the type of the object before using it.