It consists of a map in the list object. I try to match lists with the same id by comparing them through loop statements. How can I convert to lambda?
List<Map<String, String>> combineList = new ArrayList<>(); // Temp List
for(Map titleMap : titleList) { // Name List
for(Map codeMap : codeList) { // Age List
if(titleMap.get("ID").equals(codeMap.get("ID"))) { // compare Id
Map<String,String> tempMap = new HashMap<>();
tempMap.put("ID", titleMap.get("ID"));
tempMap.put("NAME", titleMap.get("NAME"));
tempMap.put("AGE", codeMap.get("AGE"));
combineList.add(tempMap);
}
}
}
You are already doing it in efficient manner. So if you want you could change same code to just use stream().forEach or if want to use streams more do it as below:
titleList.stream()
.forEach(titleMap ->
combineList.addAll(
codeList.stream()
.filter(codeMap -> titleMap.get("ID").equals(codeMap.get("ID")))
.map(codeMap -> {
Map<String, Object> tempMap = new HashMap<>();
tempMap.put("ID", titleMap.get("ID"));
tempMap.put("NAME", titleMap.get("NAME"));
tempMap.put("ID", codeMap.get("ID"));
tempMap.put("AGE", codeMap.get("AGE"));
return tempMap;
})
.collect(Collectors.toList())
)
);
Notice that you have to filter from the codeList each time because your condition is that way. Try using a class in place of Map to be more efficient, cleaner and effective.
Related
I wanted to get a submap from predicateMap:
I have tried this:
public class first {
public static void main(String[] args)
{
TreeMap<String, String> myMap = new TreeMap<String, String>();
Predicate onlyStrings = new InstanceofPredicate( String.class );
myMap.put("Key1","1");
myMap.put("Key2","2");
myMap.put("Key3","3");
System.out.println("Before using submap: "+ myMap );
Predicate pred1 = new EqualPredicate( "1" );
Predicate pred2 = new EqualPredicate( "2" );
Predicate rule = new OrPredicate( pred1, pred2 );
Map map = PredicatedMap.decorate( myMap, onlyStrings, rule );
System.out.println("Before using submap: "+ map );
}
I am not able to get the desired submap which is the following:
Initial Map: {key1=1, key2=2, key3=3}
Output (submap): {key2=2, key3=3}
Can someone please help with this
It doesn't seems PredicatedMap do what you want to achive. It looks more like a validator when adding new values to map.
If you want to extract some values from a map base on predicate, Stream API from JDK should be enough.
If doesn't bother you to modify initial list:
myMap.entrySet().removeIf( e -> !(e.getValue().equals("1") || e.getValue().equals("2")));
If you want to keep initial list and create a new one:
Map<String, String> collect = myMap.entrySet().stream().filter(x -> x.getValue().equals("1") || x.getValue().equals("2"))
.collect(Collectors.toMap(e -> e.getKey(),e -> e.getValue()));
If you have a bigger list of value that you want to keep, you can create a set of them:
Set<String> values = Set.of("1","2");
and filter base on this set:
collect = myMap.entrySet().stream().filter(x -> values.contains(x.getValue()))
.collect(Collectors.toMap(e -> e.getKey(),e -> e.getValue()));
Or for the case with modifying initial list:
myMap.entrySet().removeIf( e -> !values.contains(e.getValue()));
Looks a bit clear if you extract values to keep as a set in my opinion.
I want to convert a javax.persistence.Tuple into a HashMap, but like this, it inserts the last element of the tuple and takes also the alias and data type. How can I improve this method so it takes values of the tuple?
public Map<String, Object> tuplesToMap(List<Tuple> data){
Map<String, Object> values = new HashMap<>();
data.forEach(tuple -> {
tuple.getElements().forEach(
element -> {
values.put(element.getAlias(), tuple.get(element));
}
);
});
return values;
}
with java 8 is simply :
return data.stream()
.collect(Collectors.toMap(
t -> t.get(0, String.class),
t -> t.get(1, Object.class)));
Seems to be working :
public static List<Map<String/*UPPERCASE*/, Object>> jpaTuplesToMaps(
List<javax.persistence.Tuple> data
){
return data.stream()
.map(tuple -> { // per each tuple of the input List
// creating a new HashMap
Map<String, Object> resultItem = new HashMap<>();
// filling the created HashMap with values of
tuple.getElements().forEach( // each column of the tuple
col -> { resultItem.put(col.getAlias(), tuple.get(col)); }
);
// returning the created HashMap instead of the current Tuple
return resultItem;
})
// collecting & returning all the created HashMap-s as a List
.collect(Collectors.toList());
}
But usualy both single & list conversions are required, so let's combine them :
public static Map<String/*UPPERCASE*/, Object> jpaTupleToMap(
javax.persistence.Tuple data /*CASE INSENSITIVE*/
){
Map<String, Object> result =
new HashMap<>(); // exactly HashMap since it can handle NULL keys & values
data.getElements().forEach(
col -> { result.put(col.getAlias(), data.get(col)); }
);
return result;
}
//-------------------------
public static List<Map<String/*UPPERCASE*/, Object>> jpaTuplesToMaps(
List<javax.persistence.Tuple> data /*CASE INSENSITIVE*/
){
return data.stream() // List<Tuple> -> Tuple1,..TupleN
.map(tuple -> jpaTupleToMap(tuple)) // Tuple1 -> HashMap1,..TupleN -> HashMapN
.collect(Collectors.toList()); // HashMap1,..HashMapN -> List
}
The element.getAlias() you're using as the key for the hashmap is probably same for some of the elements.
Map keys are unique, meaning, if you insert entries (1, "one") and then (1, "two"), the first value will be overridden by the latter. If you want to have multiple values mapped to one key, use Map<String, Collection<Object>>, or a Multimap from Guava, which is exactly the same thing.
You can insert into multimap with this function - if the key is not in the map, create a new ArrayList and add it to the map, otherwise return the existing one. Then, insert the value to the list:
values
.computeIfAbsent(element.getAlias, k -> new ArrayList<>())
.add(tuple.get(element));
I have a HashSet of (a hashmap of (string and list of (hashmap of (two strings))))
HashSet<HashMap<String1,List<HashMap<String2,HashMap<String3,String4>>>>>
Now, I need to search with String inputs (StrA and StrB) and this should search the HashSet on
StrA-->String1
StrB-->String2
and it should return the hashMap of String 3 and String 4.
This is what I tried.
HashSet<HashMap<String,List<HashMap<String,HashMap<String,String>>>>> ObjList;
public void getElement(String strA, String strB) {
if(ObjList.contains(strA) && ObjList.contains(strB))
System.out.println("Yes");
}
A solution using Streams would be :
HashSet<HashMap<String, List<HashMap<String, HashMap<String, String>>>>> fooSet = //;
String string1 = "string1";
String string2 = "string2";
HashMap<String, String> mapFound;
mapFound = fooSet.stream() // iterate over HashSet
.filter(map -> map.containsKey(string1)) // keep maps that contains string1
.findFirst() // take first map that match
.orElseGet(HashMap::new) // take it really (or create new Map)
.getOrDefault(string1, new ArrayList<>()) // take the List associated as value,or new List if not exists
.stream() // iterate over the list
.filter(map -> map.containsKey(string2)) // keep maps that contains string2
.findFirst() // take first map that match
.orElseGet(HashMap::new) // take it really (or create new Map)
.getOrDefault(string2, new HashMap<>()); // take HashMap associated as value, or new Map if not found
Solution with classic for each loop would be :
HashMap<String, String> mapFound;
for (HashMap<String, List<HashMap<String, HashMap<String, String>>>> map : fooSet) {
if (map.containsKey(string1)) {
List<HashMap<String, HashMap<String, String>>> list = map.get(string1);
for(HashMap<String, HashMap<String, String>> map2 : list){
if(map2.containsKey(string2)){
mapFound = map2.get(string2);
}
}
}
}
There is no other choice than iterating both, the outer Set and the inner List (untested):
HashSet<HashMap<String1,List<HashMap<String2,HashMap<String3,String4>>>>> outer = //...
HashMap<String3,String4> result =
outer.stream()
.findFirst(map1-> map1.containsKey(string1))
.get()
.stream()
.findFirst(map2-> map2.containsKey(string2))
.get();
i'm pretty new when it comes to Java but i'll hopefully clear this up.
I currently have one class and within that class i have a TreeMap called "departments" which takes an argument of >:
TreeMap <String, List<String>> department;
Within each department such as HR, Builders etc there are a list of names of people who work there. Such as:
HR: Janet, Jones, Bob
What i'd like to do is search through department to find all departments (keys) that contain someone who's called "bob" for instance and add them to a collection to make a return.
Can anyone help with this, i've been pulling my hair out for a few days! So far i'm this far with the method although clearly nowhere near complete!
public List<String> selectValues( String... aValue)
{
for(String eachDept : department.keySet()){
Collection<String> peopleInTheDept = department.get(eachDept);
for(String person : aValue){
if(peopleInTheDept.contains(person)){
result.add(person);
}
}
}
System.out.println(result);
}
Just like OH GOD SPIDERS predicted, there is a Java 8 stream solution:
TreeMap <String, List<String>> department = new TreeMap<>();
department.put("AB", Arrays.asList("Bob", "Truus", "Miep"));
department.put("CD", Arrays.asList("Jan", "Kees", "Huub"));
department.put("EF", Arrays.asList("Jan", "Piet", "Bert"));
String aValue = "Jan";
Map<String,List<String>> result = department.entrySet().stream()
// filter out those departments that don't contain aValue
.filter(entry -> entry.getValue().contains(aValue))
// collect the matching departments back into a map
.collect(Collectors.toMap(k -> k.getKey(), k -> k.getValue()));
// print the result
result.forEach((k,v)-> System.out.println(k + " " + v.toString()));
Which prints:
EF [Jan, Piet, Bert]
CD [Jan, Kees, Huub]
Pre Java 8 solution:
Map<String, List<String>> result2 = new TreeMap<>();
for(String eachDept : department.keySet()){
List<String> peopleInTheDept = department.get(eachDept);
if(peopleInTheDept.contains(aValue)){
result2.put(eachDept, department.get(eachDept));
}
}
for (String s : result2.keySet()){
System.out.println(s + " " + result2.get(s));
}
This prints exactly the same as my Java 8 code.
Here is some java 8 Streams fancy solution to get the information and fill your list.
public void selectValues(String... values)
{
for(String value : values) {
results.addAll(department.entrySet()
.stream()
.filter(entry -> entry.getValue().contains(value))
.map(entry -> entry.getKey())
.collect(Collectors.toList()));
}
}
What I understand that you need a list of department who's Value contain certain name. Here is the solution of Java 8 version.
public static void main(String[] args) {
// Initialization of map
Map<String, List<String>> department = new TreeMap<>();
department.put("HR", new ArrayList<>());
department.put("ACC", new ArrayList<>());
department.put("MK", new ArrayList<>());
department.get("HR").add("bob");
department.get("HR").add("John");
department.get("ACC").add("Kim");
department.get("ACC").add("bob");
department.get("MK").add("XXX");
// Here is the solution
// depts is a list of string which contains the name of
// department who's value contains 'bob'
List<String > depts = department.entrySet()
.stream()
.filter(i -> i.getValue().contains("bob"))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// Printing out the result
depts.stream().forEach(System.out::println);
}
In traditional way
List<String> depts = new ArrayList<>();
for (Map.Entry<String , List<String >> it :
department.entrySet()) {
if (it.getValue().contains("bob"))
depts.add(it.getKey());
}
Java8's streams is certainly an elegant solution...but if you are restricted with the use of java 8 then how about your departments be of type TreeMap<String, Set<String>>. If you insist in using a list its very similiar. Just change the Set to List. There is a contains method in List interface too.
TreeMap<String, List<String>> departments = new TreeMap<String, List<String>>();
ArrayList<String> myList = new ArrayList<String>();
myList.add("person1");
departments.put("dep1", myList);
String[] aValue = {"person1","person2"};
public void selectValues( String... aValue)
{
for(String eachDept : departments.keySet()){
List<String> peopleInTheDept = departments.get(eachDept);
for(String person : aValue){
if(peopleInTheDept.contains(person)){
result.add(person)
}
}
}
System.out.println(result);
}
Something similar to this maybe?
I have two lists of Map<String, Object> as shown below:
List1=[ {ID=1, actor="A", film="AA"},
{ID=1, actor="B", film="AA"} ]
List2={ [ID = 1, director="C"] }
Result = { [ID=1, actor="A", film="AA", director="C"],
[ID=1, actor="B", film="AA", director="C"] }
I want to use the Stream class in Java 8 to join these lists.
How do I join the to get the value of Result shown?
Is the Stream class in Java 8 fast and stable if List1 and List2 are very big?
Ah now I understand what you want :)
I don't know if there is a better way with streams but here is a solution which would work.
List<Map<String, String>> resultList = l1.stream()
.map(m1 -> {
Map<String, String> map = new HashMap<>();
map.putAll(m1);
l2.stream()
.filter(m2 -> map.get("ID").equals(m2.get("ID")))
.findFirst()
.ifPresent(m2 -> map.put("director", m2.get("director")));
return map;
})
.collect(Collectors.toList());
The above code generates a new List resultList and does not modify the other lists List1 and List2. If it does not matter if List1 gets modified or not you could do it in a cleaner, more readable way.
l1.forEach(m1 -> l2.stream()
.filter(m2 -> m1.get("ID").equals(m2.get("ID")))
.findFirst()
.ifPresent(m2 -> m1.putIfAbsent("director", m2.get("director"))));
This way the entries of list1 get modified. So with the above example list1 is becomes the joined list. But it's actually good practice to have methods without any side effects. So I would not prefer the above example.
I would recommend a method getJoinedList which returns a new List and does not modify the other lists. And in this case I would not use streams but the old-fashioned for-loop.
private static List<Map<String, String>> getJoinedList(
List<Map<String, String>> l1, List<Map<String, String>> l2) {
List<Map<String, String>> result = new ArrayList<>();
for (Map<String, String> m1 : l1) {
Map<String, String> newMap = new HashMap<>();
newMap.putAll(m1);
for (Map<String, String> m2 : l2) {
if (m1.get("ID").equals(m2.get("ID"))) {
newMap.put("director", m2.get("director"));
break;
}
}
result.add(newMap);
}
return result;
}
Then you just can call the method like this.
List<Map<String, String>> joinedList = getJoinedList(l1, l2);
If performance matters, you should first build an index of directors:
Map<Object, Object> directors = list2.stream()
.collect(Collectors.toMap(m -> m.get("ID"), m -> m.get("director")));
Then you can merge the directors to the list entries easily:
list1.stream().forEach(m -> m.put("director", directors.get(m.get("ID"))));
Accesing the director via a Map will be faster than searching the director for each list entry.