TreeMap Format:
TreeMap<String, ArrayList<Double>> mapName = new TreeMap<>();
I'm trying to test the ArrayList<Double> for negative values. This is for a method so my string values aren't always consistent. I've tried to pull the values by using mapName.Values() but this is probably the wrong way to go about it.
If you want to know if there is a single negative number in the whole treeMap:
mapName.values().stream()
.flatMap(Collection::stream)
.anyMatch(d -> d < 0);
If you want to put your hand on the lists which have at least one negative number:
mapName.entrySet().stream()
.filter(entry -> entry.getValue().stream().anyMatch(d -> d < 0))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Related
I have a String a = "1x^2 2x^3 3x^4 4x^4 " and I want to store the power in each term as key and coefficient as value to treeMap. Since there is two same power with different coefficients, I need to sum up coefficients so that the result is {2=1,3=2,4=7}. Because treemap.put(key) can only override the previous value with the same key so I could only get the result as{2=1,3=2,4=4}. How to solve that?
It is recommended to use Map::merge function to accumulate the values for multiple identical keys:
Map<Integer, Integer> terms = new TreeMap<>();
for (String term : a.split("\\s+")) {
String[] pair = term.split("x\\^");
terms.merge(Integer.valueOf(pair[1]), Integer.valueOf(pair[0]), Integer::sum);
}
System.out.println(terms);
Output:
{2=1, 3=2, 4=7}
Using Stream API this can be resolved using Collectors.toMap in a similar way using Integer::sum as a merge function:
String a = "1x^2 2x^3 3x^4 4x^4 ";
Map<Integer, Integer> terms = Arrays.stream(a.split("\\s+")) // Stream<String>
.map(t -> t.split("x\\^")) // Stream<String[]>
.collect(Collectors.toMap(
t -> Integer.valueOf(t[1]), // power as key
t -> Integer.valueOf(t[0]), // coefficient as value
Integer::sum, // add coefficients for the same power
TreeMap::new // supply TreeMap as result
));
System.out.println(terms);
Output:
{2=1, 3=2, 4=7}
I have an object:
class Sample
{
String currency;
String amount;
}
I want an output map with sum of all objects of a specific currency.
Example-
INR 40
USD 80
EUR 20
Pointer. I have been working with the following code but its not working as I expected. You can use this code as reference:
Map<String, Double> finalResult = samples
.stream()
.collect(Collectors.toMap(
Sample::getCurrency,
e -> e.getAmount()
.stream()
.sum()));
You need to use groupingBy with summingDouble and not toMap:
Map<String, Double> finalResult = samples
.stream()
.collect(Collectors.groupingBy(
Sample::getCurrency,
Collectors.summingDouble(Sample::getAmount)
));
I consider amount is of type Double and your example is not correct (String amount;)
Just wanted to offer the following alternative for future consideration. I am also presuming you meant double for the amount as well as having the appropriate getters. You could have used Collectors.toMap as long as you included a merge function. It looks like you had the right idea but the wrong syntax.
List<Sample> samples =
List.of(new Sample("USD", 10), new Sample("USD", 30),
new Sample("INR", 40), new Sample("INR", 90),
new Sample("EUR", 20), new Sample("EUR", 50));
The third argument to toMap is a merge function to properly handle duplicates. In this cases it computes a sum of the values for each key as they are encountered.
Map<String, Double> result = samples.stream()
.collect(Collectors.toMap(
Sample::getCurrency, Sample::getAmount, Double::sum));
result.entrySet().forEach(System.out::println);
prints
EUR=70.0
USD=40.0
INR=130.0
If you really want your class to store the amount as a String, you can replace Sample::getAmount with sample->Double.valueOf(sample.getAmount()) to convert the String to a Double. But since you will probably be using these values repeatedly in computations, it is best, imo, to store the amount in its most frequently used form when the class instances are created.
Map<String, Double> finalResult = samples.stream().collect(
Collectors.groupingBy(
(Sample::getCurrency),
Collectors.summingDouble(
sample -> { return Double.parseDouble(sample.getAmount());
})));
I want a specific key from the HashMap based on a specific condition for the values. For example:
My HashMap is of the type <String,Integer>.
Map<String,Integer> getValuesInMap = new HashMap<String,Integer>();
Output = {Python=1, Java=1, OOPS=2, language=1, Ruby=3, Hey=1}
I want to retrieve the keys from this map where the integer count (i.e. value) is more than 1.
Well HashMap is not made for this kind of operations, so you can either do manually, or use Stream:
getValuesInMap.entrySet()
.stream()
.filter(e -> e.getValue() > 1)
.map(e -> e.getKey())
.collect(Collectors.toList());
If you are using Java greater than 1.7, you can use streams for that as shown below
Map<String,Integer> map = new HashMap<>();
map.put("Python", 1);
map.put("Java", 1);
map.put("OOPS", 2);
map.put("Language", 1);
map.put("Ruby", 3);
map.put("Hey", 1);
List<String> collect = map.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.map(entry -> entry.getKey())
.collect(Collectors.toList());
System.out.println(collect);
Use Collection.removeIf on the map’s values:
getValuesInMap.values().removeIf(count -> count <= 0);
System.out.println(getValuesInMap);
Be aware that the above will actually remove entries from your Map. If you need to preserve the original Map, make a copy:
Map<String, Integer> copy = new LinkedHashMap<>(getValuesInMap);
copy.values().removeIf(count -> count <= 0);
System.out.println(copy);
I have a map ,the Integer stands for the frequency and the Set stands for a Set of words ,Now I want to reduce this map to get the frequency of the set with the most words ,and the return the frequency and the number of words in that Set with a pair
public static Map<Integer, Set<String>> getCounts(In in)
My instinct tells me this is ok, this is what I think :
initial
Compare each word set separately,once the sum of words in a Set greater than the previous recorded, Update the pair
get the pair
but I get stuck as soon as I start ....
var temp = new Pair<Integer,Integer>(0, 0);
Stream.of(wordCounts)
.reduce()
Note that you might want to think about what you want to output when the map is empty.
You can use the convenient max method on streams
var pair = wordCounts.entrySet().stream()
.map(x -> new Pair<>(x.getKey(), x.getValue().size()))
.max(Comparator.comparing(Pair::getSecond));
This gives you an optional pair. The optional will be empty when the map is empty.
If you really want to use reduce, you can. Just change the max call to:
.reduce((a, b) -> a.getSecond() >= b.getSecond() ? a : b);
I hope I understood this correctly:
map.entrySet().stream().max(Comparator.comparing(x -> x.getValue().size()))
.map(x -> new Map.entry(x.getKey(), x.getValue().size()))
.orElse(new Map.entry(0, 0));
Map is defined as:
Map<Integer,String> map = new HashMap<>();
map.put(2,"ram");
map.put(3,"ram");
map.put(4,"gopal");
map.put(5,"madan");
map.put(6,"shyam");
map.put(7,"gopal");
map.put(8,"ram");
My expected output is List which contains only keys for which there is no duplicate values.
5
6
My approach and thought process:
Thought process 1 :
I would take map.entrySet().stream().map(....) and then take another stream inside map and filter the values for which duplicate values are present.
The approach soon got wasted as the first indexed value would be again compared in the nested stream and i would happen to filter out all elements thus.
Thought process 2
I kept values in different List by :
List<String> subList = map.entrySet().stream()
.map((k)->k.getValue())
.collect(Collectors.toList());
and then:
map.entrySet().stream()
.filter(s ->
subList.contains(s.getValue()) )
.map(Map.Entry::getKey)
.collect(Collectors.toList());
But I am getting the output as
2
3
4
5
6
7
8
The output is obvious as the value that i am picking as s from stream i am comparing it in the pool where the value will be always present at-least one time.
I again thought then that if i could have a counter that count count and if the value is present then it would increment, but again all seems very much vague now.
Any ways in which i can iterate by index using stream, so that i can always leave the key value which i am taking and just comparing with rest of values.
will love to get a brief explanation.
You can break the task into two step. first count value repeating by groupingBy() and counting() collectors.
Map<String,Long> valueCount = map.values()
.stream()
.collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
Its result is:
{madan=1, shyam=1, gopal=2, ram=3}
second step is to find only keys which their values are not duplicate. so to attain this you can use filter() and filtering the map by previous step result.
map.entrySet()
.stream()
.filter(entry -> valueCount.get(entry.getValue())==1).map(Map.Entry::getKey)
.collect(Collectors.toList())
You can filter the values with frequency 1 while creating the subList such as:
Set<String> uniqueSet = map.values().stream()
.collect(Collectors.groupingBy(a -> a, Collectors.counting()))
.entrySet().stream()
.filter(a -> a.getValue() == 1)
.map((Map.Entry::getKey))
.collect(Collectors.toSet());
and then perform the same operation as:
Set<Integer> result = map.entrySet().stream()
.filter(e -> uniqueSet.contains(e.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
Or as Holger pointed out in the comments, instead of counting, you could do away with a Boolean value to filter unique values as:
Set<String> uniqueSet = map.values().stream()
.collect(Collectors.toMap(Function.identity(), v -> true, (a,b) -> false))
.entrySet().stream()
.filter(Map.Entry::getValue)
.map((Map.Entry::getKey))
.collect(Collectors.toSet());