Mapping Lambda Expressions that return Booleans - java

I'm trying to map a String to Lambda Expressions. The expressions take a variable(map) and either return false or run a getOrDefault on the given map variable. But for some reason, I am getting errors.
Map<String, Runnable> order_function = new HashMap<>();
order_function.put("AlternativesValues", (Map x) -> { return false; });
order_function.put("AlternativesConstituent", (Map x) -> { x.getOrDefault("orderCloseCons", false); });

The Runnable doesn't return anything. If you expand the lambda to the anonymous class implementation, you will see the void is the return type:
Runnable runnable = new Runnable() {
#Override
public void run() {
// implementation
}
};
This is in conflict with your lambda> (Map x) -> { return false; }.
Since you need an expression which takes a Map and returns a boolean, then you need Predicate<Map<? ,Boolean>> (keep the wildcard ? or replace it with whatever is needed):
Map<String, Predicate<Map<? ,Boolean>>> order_function = new HashMap<>();
order_function.put("AlternativesValues", x -> false);
order_function.put("AlternativesConstituent", map -> map.getOrDefault("orderCloseCons", false));

perhaps you wanted to use Function instead of Runnable:
Map<String, Function<Map<String, Boolean>, Boolean>> order_function = new HashMap<>();
order_function.put("AlternativesValues", x -> false);
order_function.put("AlternativesConstituent", map -> map.getOrDefault("orderCloseCons", false));
//...
boolean alternativesValues = order_function.get("AlternativesValues").apply(someMap);

If they mean to be constants, you can use enum like below.
enum OrderFunctions {
ALTERNATIVES_VALUES("AlternativesValues", map -> false),
ALTERNATIVES_CONSTITUENT("AlternativesConstituent", map -> map.getOrDefault("orderCloseCons", false));
private final String name;
private final Function<Map<String, Boolean>, Boolean> orderFunction;
OrderFunctions(String name, Function<Map<String, Boolean>, Boolean> orderFunction) {
this.name = name;
this.orderFunction = orderFunction;
}
public String getName() {
return name;
}
public Function<Map<String, Boolean>, Boolean> getOrderFunction() {
return orderFunction;
}
}
and you can use it like below.
OrderFunctions.ALTERNATIVES_CONSTITUENT.getOrderFunction().apply(someMap);

Related

Java 8 Functional Programming avoid if conditional

How do you do the equivalent of the following transform() method using pure functional programming (without the if-conditional).
Meta: I'd appreciate a title edit, I'm not sure how to word this question in "functionalese"
public class Playground {
private static Optional<Map<String,Integer>> transform(List<Tuple<String,Optional<Integer>>> input) {
if (input.stream().anyMatch(t->t.second.isEmpty())) return Optional.empty();
Map<String, Integer> theMap = input.stream()
.map(t -> new Tuple<>(t.first, t.second.get()))
.collect(Collectors.groupingBy(
t1 -> t1.first,
Collectors.mapping(t2 -> t2.second, toSingle())));
return Optional.of(theMap);
}
#Test
public void collect() {
List<Tuple<String,Optional<Integer>>> input1 = new ArrayList<>();
input1.add(new Tuple<>("foo", Optional.of(1)));
input1.add(new Tuple<>("bar", Optional.empty()));
Optional<Map<String,Integer>> result1 = transform(input1);
assertTrue(result1.isEmpty());
List<Tuple<String,Optional<Integer>>> input2 = new ArrayList<>();
input2.add(new Tuple<>("foo", Optional.of(1)));
input2.add(new Tuple<>("bar", Optional.of(2)));
Optional<Map<String,Integer>> result2 = transform(input2);
assertTrue(result2.isPresent());
assertEquals((int)1, (int)result2.get().get("foo"));
assertEquals((int)2, (int)result2.get().get("bar"));
}
private static class Tuple<T1,T2> {
public T1 first;
public T2 second;
public Tuple(T1 first, T2 second) {
this.first = first;
this.second = second;
}
}
public static <T> Collector<T, ?, T> toSingle() {
return Collectors.collectingAndThen(
Collectors.toList(),
list -> list.get(0)
);
}
}
This might work for you:
private static Optional<Map<String, Integer>> transform(
List<Tuple<String, Optional<Integer>>> input) {
return Optional.of(input)
.filter(t -> t.stream().allMatch(a -> a.second.isPresent()))
.map(
in ->
in.stream()
.filter(t -> t.second.isPresent())
.map(t -> new Tuple<>(t.first, t.second.get()))
.collect(
Collectors.groupingBy(
t1 -> t1.first, Collectors.mapping(t2 -> t2.second, toSingle()))));
}
Although my solution does not satisfy your result, I can offer a solution with the ternary operator
private static Map<String, Integer> transform(List<Tuple<String, Optional<Integer>>> input) {
return input.stream().anyMatch(t -> t.second.isEmpty()) ? Collections.emptyMap() :
input.stream()
.map(t -> new Tuple<>(t.first, t.second.get()))
.collect(Collectors.groupingBy(
t1 -> t1.first,
Collectors.mapping(t2 -> t2.second, toSingle())));
}
“pure functional programming” is not necessarily a sign of quality and not an end in itself.
If you want to make the code simpler and more efficient, which may include getting rid of the if-conditional, especially as it bears a second iteration over the source data, you can do it in various ways. E.g.
private static <K,V> Optional<Map<K,V>> transform(List<Tuple<K,Optional<V>>> input) {
final class AbsentValue extends RuntimeException {
AbsentValue() { super(null, null, false, false); }
}
try {
return Optional.of(input.stream().collect(Collectors.toMap(
t1 -> t1.first,
t2 -> t2.second.orElseThrow(AbsentValue::new),
(first,next) -> first)));
} catch(AbsentValue av) {
return Optional.empty();
}
}
When empty optionals are truly the exceptional case, you can make flagging via exception part of the method’s contract, e.g.
public static class AbsentValueException extends RuntimeException {
}
private static <K,V> Map<K,V> transform(List<Tuple<K,Optional<V>>> input)
throws AbsentValueException {
return input.stream().collect(Collectors.toMap(
t1 -> t1.first,
t2 -> t2.second.orElseThrow(AbsentValueException::new),
(first,next)->first));
}
#Test(expected = AbsentValueException.class)
public void collect1() {
List<Tuple<String,Optional<Integer>>> input1 = new ArrayList<>();
input1.add(new Tuple<>("foo", Optional.of(1)));
input1.add(new Tuple<>("bar", Optional.empty()));
Map<String,Integer> result1 = transform(input1);
}
#Test
public void collect2() {
List<Tuple<String,Optional<Integer>>> input2 = new ArrayList<>();
input2.add(new Tuple<>("foo", Optional.of(1)));
input2.add(new Tuple<>("bar", Optional.of(2)));
Map<String,Integer> result2 = transform(input2);
assertEquals((int)1, (int)result2.get("foo"));
assertEquals((int)2, (int)result2.get("bar"));
}
Even better would be not to put optionals into the list of tuples in the first place.

How to write a jqwik generator method with nested generators

Using jqwik.net, trying to generate a Rule class with a a nested RuleConfig class inside it.
The RuleConfig class has a nested ruleProps which is a Map
The statusReturnedFromApplyingRule method always returns an initialized Rule instead of using the #provide method values ??
Returned Rule:
rule:Rule{ruleId='null', inputMetricSelector=null, ruleConfig='RuleConfig{ruleType='null', ruleProps={}}'}, elements:[{}]
Here is my code:
public class RangeMatchRuleTest {
#Property
#Report(Reporting.GENERATED)
boolean statusReturnedFromApplyingRule(#ForAll("generateRule") Rule rule,
#ForAll("generateInputMapElements") Iterable<Map<String, Object>> elements) {
RangeMatchRule rangeMatchRule = new RangeMatchRule();
final RuleIF.Status status = rangeMatchRule.applyRule(rule, elements);
return RuleIF.getEnums().contains(status.toString());
}
#Provide
Arbitrary<Rule> generateRule() {
Rule rule = new Rule();
RuleConfig ruleConfig = new RuleConfig();
Map<String, Object> ruleProps = new HashMap<>();
Arbitrary<Double> lowThresholdArb = Arbitraries.doubles()
.between(0.0, 29.0);
lowThresholdArb.allValues().ifPresent(doubleStream -> ruleProps.put(Utils.LOW_THRESHOLD, doubleStream.findFirst().get()));
//lowThresholdArb.map(lowThreshold -> ruleProps.put(Utils.LOW_THRESHOLD, lowThreshold) );
Arbitrary<Double> highThresholdArb = Arbitraries.doubles()
.between(30.0, 50.0);
highThresholdArb.map(highThreshold -> ruleProps.put(Utils.HIGH_THRESHOLD, highThreshold));
ruleConfig.setRuleProps(ruleProps);
rule.setRuleConfig(ruleConfig);
return Arbitraries.create(() -> rule);
}
#Provide
Arbitrary<Iterable<Map<String, Object>>> generateInputMapElements() {
Arbitrary<Double> metricValueArb = Arbitraries.doubles()
.between(0, 50.0);
Map<String, Object> inputMap = new HashMap<>();
metricValueArb.map(metricValue -> inputMap.put(Utils.METRIC_VALUE, metricValue));
List<Map<String, Object>> inputMapLst = new ArrayList<>();
inputMapLst.add(inputMap);
return Arbitraries.create(() -> inputMapLst);
}
}
TIA
You are building the generateRule method on the wrong assumption that an arbitrary's map method performed any real action when called. This is not the case. The fact that map returns another arbitrary instance gives a strong hint.
The underlying idea you have to grasp is that a provider method - the method annotated with #Provide - is nothing but a "description" of the generation process; it will only be called once. The actual object generation happens afterwards and is controlled by the framework.
Here's a reworked generateRule method that should do what you intended:
#Provide
Arbitrary<Rule> generateRule() {
Arbitrary<Double> lowThresholdArb = Arbitraries.doubles()
.between(0.0, 29.0);
Arbitrary<Double> highThresholdArb = Arbitraries.doubles()
.between(30.0, 50.0);
Arbitrary<RuleConfig> configArb =
Combinators.combine(lowThresholdArb, highThresholdArb)
.as((low, high) -> {
Map<String, Object> ruleProps = new HashMap<>();
ruleProps.put(Utils.LOW_THRESHOLD, low);
ruleProps.put(Utils.HIGH_THRESHOLD, high);
RuleConfig ruleConfig = new RuleConfig();
ruleConfig.setRuleProps(ruleProps);
return ruleConfig;
});
return configArb.map(config -> {
Rule rule = new Rule();
rule.setRuleConfig(config);
return rule;
});
}
What you can hopefully see is that creating a generator is like dataflow programming: Starting from some base arbitraries - lowThresholdArb and highThresholdArb - you combine, map and filter those. In the end a single instance of Arbitrary must be returned.
BTW: If you want this generator to be applied each time when you need a Rule, you could write the following class:
public class RuleArbitraryProvider implements ArbitraryProvider {
#Override
public boolean canProvideFor(TypeUsage targetType) {
return targetType.isOfType(Rule.class);
}
#Override
public Set<Arbitrary<?>> provideFor(TypeUsage targetType, SubtypeProvider subtypeProvider) {
return Collections.singleton(generateRule());
}
private Arbitrary<Rule> generateRule() {
// Put here the code from above
...
}
}
and register it as a default provider.
Additional example for the Map above based on the provided answer:
#Provide
Arbitrary<Iterable<Map<String, Object>>> generateInputMapElements() {
Arbitrary<Double> metricValueArb = Arbitraries.doubles()
.between(0, 50.0);
Arbitrary<Map<String, Object>> inputMapArb =
metricValueArb.map(metricsValue -> {
Map<String, Object> inputMap = new HashMap<>();
inputMap.put(Utils.METRIC_VALUE, metricsValue);
return inputMap;
});
return inputMapArb.map(inputMap -> {
List<Map<String, Object>> inputMapLst = new ArrayList<>();
inputMapLst.add(inputMap);
return inputMapLst;
});
}

Java 8 Lambda Collectors.summingLong multiple columns?

I have POJO definition as follows:
class EmployeeDetails{
private String deptName;
private Double salary;
private Double bonus;
...
}
Currently, i have lambda expression for Group By 'deptName' as :
$set.stream().collect(Collectors.groupingBy(EmployeeDetails::getDeptName,
Collectors.summingLong(EmployeeDetails::getSalary));
Question Is it possible to Sum more than one column? I need to compute sum on both fields salary and bonus in one expression instead of multiple times?
SQL representation would be:
SELECT deptName,SUM(salary),SUM(bonus)
FROM TABLE_EMP
GROUP BY deptName;
You need to create an additional class that will hold your 2 summarised numbers (salary and bonus). And a custom collector.
Let's say you have
private static final class Summary {
private double salarySum;
private double bonusSum;
public Summary() {
this.salarySum = 0;
this.bonusSum = 0;
}
#Override
public String toString() {
return "Summary{" +
"salarySum=" + salarySum +
", bonusSum=" + bonusSum +
'}';
}
}
for holding sums. Then you need a collector like this:
private static class EmployeeDetailsSummaryCollector implements Collector<EmployeeDetails, Summary, Summary> {
#Override
public Supplier<Summary> supplier() {
return Summary::new;
}
#Override
public BiConsumer<Summary, EmployeeDetails> accumulator() {
return (summary, employeeDetails) -> {
summary.salarySum += employeeDetails.salary;
summary.bonusSum += employeeDetails.bonus;
};
}
#Override
public BinaryOperator<Summary> combiner() {
return (summary, summary1) -> {
summary.salarySum += summary1.salarySum;
summary.bonusSum += summary1.bonusSum;
return summary;
};
}
#Override
public Function<Summary, Summary> finisher() {
return Function.identity();
}
#Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Collector.Characteristics.IDENTITY_FINISH);
}
}
With these classes you can collect your results like
final List<EmployeeDetails> employees = asList(
new EmployeeDetails(/* deptName */"A", /* salary */ 100d, /* bonus */ 20d),
new EmployeeDetails("A", 150d, 10d),
new EmployeeDetails("B", 80d, 5d),
new EmployeeDetails("C", 100d, 20d)
);
final Collector<EmployeeDetails, Summary, Summary> collector = new EmployeeDetailsSummaryCollector();
final Map<String, Summary> map = employees.stream()
.collect(Collectors.groupingBy(o -> o.deptName, collector));
System.out.println("map = " + map);
Which prints this:
map = {A=[salary=250.0, bonus=30.0], B=[salary=80.0, bonus=5.0], C=[salary=100.0, bonus=20.0]}
I know you've got your answer, but here is my take(I was writing while the other was posted). There is already a Pair in java in the form of AbstractMap.SimpleEntry.
System.out.println(Stream.of(new EmployeeDetails("first", 50d, 7d), new EmployeeDetails("first", 50d, 7d),
new EmployeeDetails("second", 51d, 8d), new EmployeeDetails("second", 51d, 8d))
.collect(Collectors.toMap(EmployeeDetails::getDeptName,
ed -> new AbstractMap.SimpleEntry<>(ed.getSalary(), ed.getBonus()),
(left, right) -> {
double key = left.getKey() + right.getKey();
double value = left.getValue() + right.getValue();
return new AbstractMap.SimpleEntry<>(key, value);
}, HashMap::new)));
Grouping by is a terminal operation that yields a map. The map produced by the groupingBy in the code below is a Map<String, List<EmployeeDetails>>. I create a new stream using the Map entrySet method. I then create a new Map using Collectors.toMap. This approach uses method chaining to avoid creating another class and create more concise code.
details.stream()
.collect(Collectors.groupingBy(EmployeeDetails::getDeptName))
.entrySet()
.stream()
.collect(Collectors.toMap(x->x.getKey(), x->x.getValue()
.stream()
.mapToDouble(y -> y.getSalary() + y.getBonus())
.sum()));

Not able to get desired output while working with PartioningBy and groupingBy together

I am working with collectors' groupingBy and partioningBy functions. I an working with a list of persons, the list of persons is as follows:
List<Person> persons =
Arrays.asList(
new Person("Max", 18),
new Person("Peter", 23),
new Person("Pamela", 23),
new Person("David", 12),
new Person("Pam", 12));
What i want is to partition the list on the basis of persons whose name starts with letter "P" and then group them on the basis of their ages.
Here is my code which does the above filtration:
Map<Boolean, Map<Object, List<Person>>> rr = persons.stream()
.collect(Collectors.partitioningBy(p -> p.name.startsWith("P"),
Collectors.groupingBy(p -> p.age > 20)));
And the output which i got is:
rr = {false={false=[Max, David]}, true={false=[Pam], true=[Peter, Pamela]}}
Now, my requirement is to get only internal map from the above results. That is, i want to change the return values to:
{false=[Pam], true=[Peter, Pamela]}
That is, I want the results (or partitioned map) whose boolean value is true as returned by the partioningBy function. How can i achieve this?
You could create a custom collector (I've done it only as an exercise, please treat it as such):
static class MyCustom<T, U> implements Collector<Person, List<Person>, Map<T, List<U>>> {
private final Function<Person, T> function;
private final Predicate<Person> predicate;
private final Function<Person, U> transformingFunction;
public MyCustom(Predicate<Person> predicate, Function<Person, T> function,
Function<Person, U> transformingFunction) {
this.predicate = predicate;
this.function = function;
this.transformingFunction = transformingFunction;
}
#Override
public Supplier<List<Person>> supplier() {
return ArrayList::new;
}
#Override
public BiConsumer<List<Person>, Person> accumulator() {
return (list, person) -> {
if (predicate.test(person)) {
list.add(person);
}
};
}
#Override
public BinaryOperator<List<Person>> combiner() {
return (l1, l2) -> {
l1.addAll(l2);
return l1;
};
}
#Override
public Function<List<Person>, Map<T, List<U>>> finisher() {
return list -> {
return list.stream().collect(
Collectors.groupingBy(function, Collectors.mapping(transformingFunction, Collectors.toList())));
};
}
#Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return EnumSet.of(Characteristics.UNORDERED);
}
}
And then apply it like this:
MyCustom<Integer, String> custom = new MyCustom<>((Person p) -> p.getName().startsWith("P"),
(Person p) -> p.getAge(), Person::getName);
System.out.println(persons.stream().collect(custom)); // {23=[Peter, Pamela], 12=[Pam]}
Filter by name
Apply partitioning by age
Map<Boolean, List<Person>> p1 = persons.stream().filter(p -> p.name.startsWith("P")).collect(Collectors.partitioningBy(p -> p.getAge() > 20));

How to properly lazy initialize Map of Map of Map?

It may be a bad practice, but I haven't been able to figure out any better solution for my problem. So I have this map
// Map<state, Map<transition, Map<property, value>>>
private Map<String, Map<String, Map<String, String>>> properties;
and I want to initialize it so I don't get NullPointerException with this
properties.get("a").get("b").get("c");
I tried this one but I didn't work (obviously)
properties = new HashMap<String, Map<String, Map<String,String>>>();
Other things I tried didn't compile.
Also if you have any ideas how to avoid this nested maps, I would appreciate it.
It seems to me that you need to create your own Key class:
public class Key {
private final String a;
private final String b;
private final String c;
public Key(String a, String b, String c) {
// initialize all fields here
}
// you need to implement equals and hashcode. Eclipse and IntelliJ can do that for you
}
If you implement your own key class, your map will look like this:
Map<Key, String> map = new HashMap<Key, String>();
And when looking for something in the map you can use:
map.get(new Key("a", "b", "c"));
The method above will not throw a NullPointerException.
Please remember that for this solution to work, you need to override equals and hashcode in the Key class. There is help here. If you don't override equals and hashcode, then a new key with the same elements won't match an existing key in the map.
There are other possible solutions but implementing your own key is a pretty clean one in my opinion. If you don't want to use the constructor you can initialize your key with a static method and use something like:
Key.build(a, b, c)
It is up to you.
You need to put maps in your maps in your map. Literally:
properties = new HashMap<String, Map<String, Map<String,String>>>();
properties.put("a", new HashMap<String, Map<String,String>>());
properites.get("a").put("b", new HashMap<String,String>());
If your target is lazy initialization without NPE you have to create your own map:
private static abstract class MyMap<K, V> extends HashMap<K, V> {
#Override
public V get(Object key) {
V val = super.get(key);
if (val == null && key instanceof K) {
put((K)key, val = create());
}
return val;
}
protected abstract V create();
}
public void initialize() {
properties = new MyMap<String, Map<String, Map<String, String>>>() {
#Override
protected Map<String, Map<String, String>> create() {
return new MyMap<String, Map<String, String>>() {
#Override
protected Map<String, String> create() {
return new HashMap<String, String>();
}
};
}
};
}
You could use a utility method:
public static <T> T get(Map<?, ?> properties, Object... keys) {
Map<?, ?> nestedMap = properties;
for (int i = 0; i < keys.length; i++) {
if (i == keys.length - 1) {
#SuppressWarnings("unchecked")
T value = (T) nestedMap.get(keys[i]);
return value;
} else {
nestedMap = (Map<?, ?>) nestedMap.get(keys[i]);
if(nestedMap == null) {
return null;
}
}
}
return null;
}
This can be invoked like this:
String result = get(properties, "a", "b", "c");
Note that care is required when using this as it is not type-safe.
The only way to do it with this structure is to pre-initialise the 1st and 2nd level maps with ALL possible keys. If this is not possible to do you can't achieve what you are asking with plain Maps.
As an alternative you can build a custom data structure that is more forgiving. For example a common trick is for a failed key lookup to return an "empty" structure rather than null, allowing nested access.
You can't initialize this in one go, since you normally don't know what keys you'll have in advance.
Thus you'd have to check whether the submap for a key is null and if so you might add an empty map for that. Preferably you'd only do that when adding entries to the map and upon retrieving entries you return null if one of the submaps in the path doesn't exist. You could wrap that in your own map implementation for ease of use.
As an alternative, apache commons collections' MultiKeyMap might provide what you want.
It's impossible to use properties.get("a").get("b").get("c"); and be sure to avoid null unless you make your own Map. In fact, you can't predict that your map will contains "b" key.
So try to make your own class to handle nested get.
I think a better solution is using an object as the only key to the map of values. The key will be composed of three fields, state, transition and property.
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Key {
private String state;
private String transition;
private String property;
public Key(String state, String transition, String property) {
this.state = state;
this.transition = transition;
this.property = property;
}
#Override
public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
When you check for a value, the map will return null for a key that is not associated with a value
Map<Key, String> values = new HashMap<Key, String>();
assert values.get(new Key("a", "b", "c")) == null;
values.put(new Key("a", "b", "c"), "value");
assert values.get(new Key("a", "b", "c")) != null;
assert values.get(new Key("a", "b", "c")).equals("value");
To efficiently and correctly use an object as a key in a Map you should override the methods equals() and hashCode(). I have built thos methods using the reflective functionalities of the Commons Lang library.
I think, following is the easier way:
public static final Map<Integer, Map<Integer, Map<Integer, Double>>> A_Map = new HashMap<Integer, Map<Integer, Map<Integer, Double>>>()
{
{
put(0, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 60.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 160.0);
put(1, 1 / 13600.0);
}
});
}
});
put(1, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 260.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 560.0);
put(1, 1 / 1300.0);
}
});
}
});
}
};
Using computeIfAbsent/putIfAbsent makes it simple:
private <T> void addValueToMap(String keyA, String keyB, String keyC, String value) {
map.computeIfAbsent(keyA, k -> new HashMap<>())
.computeIfAbsent(keyB, k -> new HashMap<>())
.putIfAbsent(keyC, value);
}

Categories