How to convert list of map list<map<string, object>> to list of value of map map<string,list<string>> using steam api java 8 - java-8

I have a list of map. The map contains string as key & object as value. Most likely values also string. I want to group by one value so that I will get a set of value as key and another group of unique values as a list. Actually, list of map is couchbase select data.
e.g:
[{"id":"1", "status":"pending"},{"id":"2", "status":"download"},{"id":"3", "status":"pending"},{"id":"4", "status":"pending"}, {"id":"5", "status":"ready"},{"id":"6", "status":"download"}] => {"pending":["1","3","4"], "download":["2","6"], "ready":["5"]}

Try this out. Notice that my values are Strings NOT Objects as yours. In your case you need to cast it explicitly to String like so,
s -> (String) s.get("status")
s -> (String) s.get("id")
Map<String, List<String>> idsByStatus = listOfMap.stream().collect(
Collectors.groupingBy(s -> s.get("status"), Collectors.mapping(s -> s.get("id"), Collectors.toList())));

Related

Pass comparator into map with collectors [duplicate]

Let's say I have a list of Brand objects. The POJO contains a getName() that returns a string. I want to build a
Map<String, Brand>
out of this with the String being the name... but I want the key to be case insensitive.
How do I make this work using Java streams? Trying:
brands.stream().collect(Collectors.groupingBy(brand -> brand.getName().toLowerCase()));
doesn't work, which I think is because I'm not using groupBy correctly.
Collect the results into a case insensitive map
Map<String, Brand> map = brands
.stream()
.collect(
Collectors.toMap(
Brand::getName, // the key
Function.identity(), // the value
(first, second) -> first, // how to handle duplicates
() -> new TreeMap<String, Brand>(String.CASE_INSENSITIVE_ORDER))); // supply the map implementation
Collectors#groupBy won't work here because it returns a Map<KeyType, List<ValueType>>, but you don't want a List as a value, you just want a Brand, from what I've understood.

What are supported types for keys of hash in freemarker?

Can we use any type for keys of hash in Freemarker ?
For instance:
In Java we have:
Hash<User, Boolean> mapUserToSelected = new HashMap<>()
And in Freemarker we have:
<#list mapUserToSelected as user, selected>
<p>${user.name}</p>
<p>${selected?c}</p>
</#list>
However, we got "The following has evaluated to null or missing" for the <p>${selected?c}</p> and I am sure that it exists in the map.
If I use String for keys of hash Hash<String, Boolean> mapUserToSelected = new HashMap<>() it will work.
Is the key of hash needed to be String only?
The object mapUserToSelected can contain any Object as key, the built in ?c will convert a string to numeric. Not sure why you're applying it to Boolean.
Also, not to confuse ourselves: When we want to send the object mapUserToSelected from Logic (controller) to UI then tha's when the key must be String based on the definition of TemplateHashModel.
Example:
ModelAndView mainView = new ModelAndView();
mainView.getModel().put("usersMap", mapUserToSelected );
But the object itself can contain anything, you can get the keys list using mapUserToSelected?keys then access each the list of the keys using ?index if you are interested in the value of every key.

How to find the duplicates values in a Map with in a stream of list?

Say I have this array list:
List<Map<String,String>> fileDataList= new ArrayList<>();
fileDataList.stream().forEach(t->{
//find duplicate map values
});
The list may contain duplicate values like these:
[
{age:12,name:"john"},
{age:11,name:"Mary"},
{age:12,name:"john"}
]
Now,I would like to find the duplicate map values which match both name and age inside the stream without removing them.
I tried with HashSet, But I couldn't understand.
Holger in comments brings a point I missed. If your Map contains only of those name and age properties, you could simply do:
fileDataList.stream()
.distinct()
.collect(Collectors.toList())
And this will be enough. If, on the other hand, you have more properties and
what to filter by only some of them, you could use this utility:
fileDataList.stream()
.filter(distinctByKey(x -> Arrays.asList(x.get("name"), x.get("age")))
.collect(Collectors.toList());
You can transfre your list if Map to list of EntrySet.
List<Map.Entry<String, String>> entries = fileDataList.stream()
.flatMap(e -> e.entrySet().stream())
.collect(toList());

RedisTemplate get hash key by value

I'm very new both on Spring and Redis. I would like to know if there is a way to get the KEY by value?
My KEY is patterned like this: "{typeOfFile}:{id}:{filename}"
typeOfFile could either be "image", "html", or "pdf".
For instance, I want to get the get the KEY of an image type of file with a given fileHash and content. I'm doing it with this kind of idea:
private String getKeyByVal(final String givenFileHash, final String content) {
// get all keys that starts with "image"
Set<String> keys = redisTemplate.keys("image*");
if (keys != null) {
for (String key : keys) {
Map<Object, Object> val = redisTemplate.opsForHash().entries(key);
// check if the value of KEY is equal to the given fileHash
if (val.get("fileHash").equals(givenFileHash) && val.get("content").equals(content)) {
return key;
}
}
}
}
However, I was told that this is quite costly since I'm getting all the keys that starts with "image", and manually check all of them.
Now I'm thinking, maybe it would be much better if I can get the KEY by value. So that it would be easier to get all of its properties. Is that possible in Redis?
No, this is not possible in Redis. You can however store a reverse map in simultaneous as below:
fileHash -> "{typeOfFile}:{id}:{filename}"
This solution assumes that the file hash is unique. If the hash is not unique then you can store a set of ids with the same hash, retrieve the content for each of them and compare. Still a lot faster than the original solution.

Java API to match multiple fields in elasticsearch

Currently I query ES for a single key value pair like this:
String query_key = "abc";
String query_val = "def";
searchRequestBuilder.setQuery(QueryBuilders.matchQuery(query_key, query_val)).execute().actionGet();
Now, instead of single key-value pair, I have the following key-value pair map: Map<String,String> query_list
How do I modify the same for this?
You can use MuliMatchQuery or Boolean Query to fulfill your requirement.
ex:-
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
for (Map.Entry<String, String> entry : fields.entrySet()){
boolQuery.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
}
Set this boolQuery in your searchRequest read the elasticsearch boolQueries and use one which fits for your requirement.
The Above example will perform the AND operation among the provided fields. the field1 and field2 must match. if you want to perform the OR operation then you should use sould query you have an option to set minimum_should_match in that you can specify the minimum fields should match.

Resources