Data handling of HashMultimap - java

I have a HashMultimap
Multimap<String, String> map = HashMultimap.create();
The data I put into the map is
map.put("cpu", "i9");
map.put("hang", "MSI");
map.put("hang", "DELL");
map.put("hang", "DELL");
map.put("cpu", "i5");
map.put("hang", "HP");
map.put("cpu", "i7");
I have a stream
String joinString = map.entries().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(" OR "));
I need the output to be
(hang=HP OR hang=MSI OR hang=DELL) AND (cpu=i9 OR cpu=i5 OR cpu=i7)
I need an AND in between the keys. How can I do that?

Use the Map view:
String joined = map.asMap()
.entrySet()
.stream()
.map(e -> e.getValue()
.stream()
.map(v -> e.getKey() + "=" + v)
.collect(Collectors.joining(" OR ", "(", ")")))
.collect(Collectors.joining(" AND "));

Of course schmosel beat me, but here a slightly different api/usage:
String joined = map.keySet() // keySet() instead of asMap()
.stream().map(k
-> String.format( // string.format instead of concatenation ;)
"(%s)",
map.get(k).stream() // map.get(k) instead of e.getValue()
.map(v
-> String.format("%s=%s", k, v))
.collect(Collectors.joining(" OR "))
)
).collect(Collectors.joining(" AND "));

Related

How I can convert Map to String?

This is my map:
Map<String, Object> params = new HashMap<>();
params.put("topicRef", "update-123456-78925-new-u1z1w3");
params.put("parentRef", "update-123456-78925-new-u1z1w3");
Script script = new Script(ScriptType.INLINE, "painless",
String.format("ctx._source.parentRef = params.parentRef; ctx._source.topicRef = params.topicRef"),
params);
request.setScript(script);
I want to convert my map into a string but I would like to change the pattern for e.g.:
"ctx._source.key = value;ctx._source.key = value"
I want to add to key value a prefix ctx._source.key and a suffix " =" (space and equal), then I would like to separate each entry with a semicolon.
String formattedMap = params.entrySet().
stream()
.map(e -> "ctx._source." + e.getKey() + " = " + e.getValue())
.collect(Collectors.joining(","));
Try something like this:
Map<String, String> yourMap = /*...*/;
StringBuilder bob = new StringBuilder();
yourMap.forEach((key, value) -> bob.append(key).append("=").append(value).append(";"));
String result = bob.toString();
If necessary you could remove the last ; on result via String.concat().
You could stream your Map's entries, then use the map operation to map each entry to the formatted String and ultimately join each element with the collect(Collectors.joining(";")) operation.
Map<String, Object> params = new HashMap<>();
params.put("topicRef", "update-123456-78925-new-u1z1w3");
params.put("parentRef", "update-123456-78925-new-u1z1w3");
String result = params.entrySet().stream()
.map(entry -> String.format("%s%s%s%s", "ctx._source.", entry.getKey(), " =", entry.getValue()))
.collect(Collectors.joining(";"));
System.out.println(result);
Here is a link to test the code
https://www.jdoodle.com/iembed/v0/rrK
Output
String result = params.entrySet()
.stream()
.map(x -> "ctx._source." + x.getKey() + " = " + x.getValue())
.reduce((x, y) -> x + ";" + y).get();

flatMap triple nested streams

I'm trying to flatMap and get a result of list of Strings from three Lists. I somehow was able to do by the following code. The code is working but somehow I feel I have over complicated it. Can someone please give me some advice which can improve it in a better way
countries.stream()
.map(country -> titles.stream()
.map(title -> games.stream()
.map(game -> Arrays.asList(game, country + "_" + title + "_" + game))
.collect(toList()))
.collect(toList()))
.collect(toList())
.stream()
.flatMap(Collection::stream)
.flatMap(Collection::stream)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
For clarification of the logic, a traditional approach would look like:
Set<List<String>> results = new HashSet<>();
for (String country : countries) {
for (String title : titles) {
for (String game : games) {
results.add(Arrays.asList(game, country + "_" + title + "_" + game));
}
}
}
You can do this in two steps:
first create concatenation of countries and titles list:
List<String> countriesTitle = countries.stream()
.flatMap(country -> titles.stream()
.map(title -> country + "_" + title))
.collect(Collectors.toList());
then by previous result create list of concatenation country+"_"+title+"_"+game string:
Stream.concat(games.stream(),
games.stream()
.flatMap(game -> countriesTitle.stream()
.map(countryTitle -> countryTitle + "_" + game)))
.collect(Collectors.toList());
Updated answer:
games.stream()
.flatMap(game -> countries.stream()
.flatMap(country -> titles.stream()
.flatMap(title -> Stream.of(game, country + "_" + title + "_" + game))))
.collect(Collectors.toSet());

Writing data to a .CSV file using a Java 8 Stream

I am trying to output 2 collections of data to a .csv file in Java.
Collection 1 = customer names
Collection 2 = customer references
I want the .csv to present as:
Smith:839393,
Johnson:283940,
Collins:293845
My code:
private void writeDataToFile() throws IOException {
FileWriter writer = new FileWriter("src/test/resources/custData.csv");
List<String> customers = new ArrayList<>(customers);
List<String> references = new ArrayList<>(references);
String collect1 = customers.stream().collect(Collectors.joining(",\n" + ":"));
String collect2 = references.stream().collect(Collectors.joining(",\n" + ":"));
writer.write(collect1 + collect2);
writer.close();
}
My output:
Smith,
:Johnson,
:Collins839393,
:283940,
:293845
How can I achieve the desired output?
You can do this way if both lists have the same size. Use IntStream.range to iterate the lists and then map the data. Then collect joining ,\n
String res = IntStream.range(0, customers.size())
.mapToObj(i -> customers.get(i) + ":" + references.get(i))
.collect(Collectors.joining(",\n"));
Assuming both of your collections have same number of elements you can try this
String output =
IntStream.rangeClosed(0, customers.size()-1)
.boxed()
.map(i -> customers.get(i) + ":" + references.get(i))
.collect(Collectors.joining("\n"));
writer.write(output);
I assume customers and references have the same size. You can iterate between 0 and customers.size() and combine the elements of both lists:
customers.get(i) + ":" + references.get(i) + ",\n"
Try this:
String output = IntStream.range(0, customers.size()).boxed()
.map(i -> customers.get(i) + ":" + references.get(i) + ",\n").collect(Collectors.joining());
What you are trying to do is called collection zipping.
See full article here
In pure java you can do the solutions
IntStream.range(0, Math.min(customers.size(), references.size()))
.mapToObj(i -> customers.get(i) + ":" + references.get(i))
.collect(Collectors.joining(",\n"));
If you have guava you can do it bit nicer
Streams
.zip(customers.stream(), references.stream(), (customer, reference) -> customer + ":" + reference)
.collect(Collectors.joining(",\n"));

Convert Stream to String in Java

I want to convert a Stream of a Map<> into a String, to append it to a textArea. I tried some methods, the last with StringBuilder, but they don't work.
public <K, V extends Comparable<? super V>> String sortByAscendentValue(Map<K, V> map, int maxSize) {
StringBuilder sBuilder = new StringBuilder();
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
BufferedReader br = new BufferedReader(new InputStreamReader((InputStream) sorted));
String read;
try {
while ((read=br.readLine()) != null) {
//System.out.println(read);
sBuilder.append(read);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sorted.limit(maxSize).forEach(System.out::println);
return sBuilder.toString();
}
You can collect the entries into a single String as follows:
String sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.map(e-> e.getKey().toString() + "=" + e.getValue().toString())
.collect(Collectors.joining (","));
Consider slight change to #Eran's code, with regard to the fact that HashMap.Entry.toString() already does joining by = for you:
String sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.map(Objects::toString)
.collect(Collectors.joining(","));
It is easy to do this, you can use the Steams API to do this. First, you map each entry in the map to a single string - the concatenated string of key and value. Once you have that, you can simply use the reduce() method or collect() method to do it.
Code snippet using 'reduce()' method will look something like this:
Map<String, String> map = new HashMap<>();
map.put("sam1", "sam1");
map.put("sam2", "sam2");
String concatString = map.entrySet()
.stream()
.map(element-> element.getKey().toString() + " : " + element.getValue().toString())
.reduce("", (str1,str2) -> str1 + " , " + str2).substring(3);
System.out.println(concatString);
This will give you the following output:
sam2 : sam2 , sam1 : sam1
You can also use the collect()' method instead ofreduce()` method. It will look something like this:
String concatString = map.entrySet()
.stream()
.map(element-> element.getKey().toString() + " : " + element.getValue().toString())
.collect(Collectors.reducing("", (str1,str2) -> str1 + " , " + str2)).substring(3);
Both methods give the same output.

Convert HashMap into String with keys and values [duplicate]

This question already has answers here:
How to convert map to url query string?
(20 answers)
Closed 4 years ago.
I want to create util method which converts HashMap into long String with keys and values:
HashMap<String, String> map = new LinkedhashMap<>();
map.put("first_key", "first_value");
map.put("second_key", "second_value");
I need to get this end result:
first_key=first_value&second_key=second_value
You can use streams:
String result = map.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
Note: You should probably use an url encoding. First create a helper method like this:
public static String encode(String s){
try{
return java.net.URLEncoder.encode(s, "UTF-8");
} catch(UnsupportedEncodingException e){
throw new IllegalStateException(e);
}
}
And then use that inside of your stream to encode the key and value:
String result = map.entrySet().stream()
.map(e -> encode(e.getKey()) + "=" + encode(e.getValue()))
.collect(Collectors.joining("&"));
Try this:
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : map.entrySet()) {
sb.append(entry.getKey());
sb.append('=');
sb.append(entry.getValue());
sb.append('&');
}
sb.deleteCharAt(sb.length() - 1);
String result = sb.toString();
map.toString().replace(",","&")
The output Map::toString is not much different from the output you want. Compare:
{first_key=first_value, second_key=second_value}
first_key=first_value&second_key=second_value
Just perform the right character replacement:
map.toString().replaceAll("[{ }]", "").replace(",","&")
"[{ }]" is regex matching all the brackets {} and the space - those to be removed (replaced with "").
, to be replaced with & character.

Categories

Resources