Stream and Filter operations on a Map - filter

I have an EdmPortfolio type that has id (int), name (String) and tags which is a map as its members.
EdmPortfolio say has an id 1, and name as Portfolio1 and Map could have the following values,
analyst, John
region, US
I have a List, At the end i want to have a Map which has all the map values combined from all portfolios. Another EdmPortfolio might have the id as 2, name as Portfolio2 and Map with values analyst, Smith
region , UK
I want to have a combined Map with Values
region 'US','UK'
analyst 'John','Smith'
analyst and region are the keys to the map.
It has both the maps combined. I have the following code but i am a little lost
List<Map<Tag,String>> portfolioTagsList = new ArrayList<>();
for (EdmPortfolio edmPortfolio : edmPortfolioList) {
Map<Tag,String> portfolioTags = edmPortfolio.getPortfolioTags().entrySet()
.stream()
.filter(e -> (e.getValue() != ""|| e.getValue() !=null))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
portfolioTagsList.add(portfolioTags);
}
Map<Tag,String> finalTags = portfolioTagsList.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.joining(",",Map.Entry::getValue)));
I am getting nonstatic method cannot be referenced from static context. How do i achieve this?
Thanks for your time

I'd do something like:
Map<Tag,String> finalTags = edmPortfolioList.stream()
.flatMap(edmPortfolio -> edmPortfolio.getPortfolioTags().entrySet().stream())
.filter(e -> (e.getValue() != "" || e.getValue() !=null)) // this seems weird, but just keeping
.collect(Collectors.groupingBy(e -> e.getKey(),
Collectors.mapping(ev -> ev.getValue(),
Collectors.joining(",")));
BTW: Any reason to break that in two streams?

Unfortunately, “nonstatic method cannot be referenced from static context” is the error that javac often ends up when type inference fails, especially in the context of method references or lambda expressions. The actual cause could be a wrong generic type parameter, a forgotten import statement, the use of a lambda expression or method reference at an inappropriate place, or even a misplaced or forgotten brace somewhere.
In your case, it’s Collectors.joining(",",Map.Entry::getValue) as that collector has no parameter of a function type that could accept a method reference.
You should use Collectors.mapping(Map.Entry::getValue, Collectors.joining(",")) instead.
Besides that, follow BrunoJCM’s suggestion to use a single stream operation and pay attention to the filter condition. e.getValue() != "" || e.getValue() !=null makes no sense as a reference can never be both, a reference to "" and the null reference, hence, this condition is always fulfilled. You most likely wanted to express that the string must not be null and not an empty string. In this regard, you should not compare strings by reference but use equals. For testing for an empty string, there is the alternative to use isEmpty() instead of equals(""). So the condition should be e.getValue()!=null && !e.getValue().isEmpty(). Mind the order, as we can invoke isEmpty() only after having verified that it is not null.

Related

Why cant nullable arrays/hashmaps be accessed using []

When I have a nullable array/list/hashmap such as
var x: ArrayList<String>? = null
I know can access the element at index 1 like so
var element = x?.get(1)
or I could do it in a unsafe way like this
var element = x!![1]
but why can't I do something like this
var element = x?[1]
what's the difference between getting elements from an array using the first example and the last example, and why is the last example not allowed?
In the first example, you're using the safe call operator ?. to call the get function with it.
In the second example, you're using the [] operator on the non-nullable return value of the x!! expression, which of course is allowed.
However, the language simply doesn't have a ?[] operator, which would be the combination of the two. The other operators offered are also don't have null-safe variants: there's no ?+ or ?&& or anything like that. This is just a design decision by the language creators. (The full list of available operators is here).
If you want to use operators, you need to call them on non-nullable expressions - only functions get the convenience of the safe call operator.
You could also define your own operator as an extension of the nullable type:
operator fun <T> List<T>?.get(index: Int) = this?.get(index)
val x: ArrayList<String>? = null
val second = x[2] // null
This would get you a neater syntax, but it hides the underlying null handling, and might confuse people who don't expect this custom extension on collections.

How to Use DocumentDb, LINQ, and F# to return multiple properties?

Getting an error when running the F# version of the code below while the C# version below works. Any ideas about on how to return multiple documentdb properties from a linq query with F# in general?
2016-12-29T23:57:08.504 Exception while executing function: Functions.GetTags. mscorlib: Exception has been thrown by the target of an invocation. mscorlib: One or more errors occurred. Microsoft.Azure.Documents.Client: Constructor invocation is not supported.
C#
var userTagsQuery =
userDocument.Where(user => user.topics != null && user.education != null)
.Select(user => new {topics=user.topics, education=user.education});
F#
type UserTagRecord = {topics : string list; education : string list}
let userTagsQuery =
user.Where(fun user -> user.topics <> null && user.education <> null)
.Select(fun user -> {topics=user.topics :?> string list; education=user.education :?> string list})
The error says "Constructor invocation is not supported". This is a sensible limitation, most LINQ providers have it.
In your F# code, the constructor call is the record creation. F# records are compiled as classes with a bunch of read-only properties and a single constructor that takes values for those properties as parameters. According to the error message, calling this constructor is not supported. Bad luck.
An interesting thing to notice is that C# anonymous types (employed in your C# code) work in exactly same way as F# records - they are classes with a bunch of read-only properties and a single constructor, - and yet, they are supported. Handing C# anonymous types as a special case is, again, a common practice for LINQ providers. Many LINQ providers would handle it in a more generalized way that would cover F# records as well, but in this case it is apparently not the case. If I were you, I would open an issue about it.
What you can try is replace your record with a class with mutable properties, and construct it with property initialization syntax:
type UserTagRecord() =
member val topics : string list = [] with get, set
member val education : string list = [] with get, set
let userTagsQuery =
user
.Where(fun user -> user.topics <> null && user.education <> null)
.Select(fun user -> UserTagRecord( topics=user.topics :?> string list, education=user.education :?> string list ) )
I would also go out on a limb here and suggest that you might have further trouble with using F# lists. First, DocumentDb might not like them by themselves, and second, I don't know what user.topics and user.education are, but I'm pretty sure that they're not a subclass of string list, so your casts will probably fail.

Sense of Optional.orElse() [duplicate]

Why does this throw a java.lang.NullPointerException?
List<String> strings = new ArrayList<>();
strings.add(null);
strings.add("test");
String firstString = strings.stream()
.findFirst() // Exception thrown here
.orElse("StringWhenListIsEmpty");
//.orElse(null); // Changing the `orElse()` to avoid ambiguity
The first item in strings is null, which is a perfectly acceptable value. Furthermore, findFirst() returns an Optional, which makes even more sense for findFirst() to be able to handle nulls.
EDIT: updated the orElse() to be less ambiguous.
The reason for this is the use of Optional<T> in the return. Optional is not allowed to contain null. Essentially, it offers no way of distinguishing situations "it's not there" and "it's there, but it is set to null".
That's why the documentation explicitly prohibits the situation when null is selected in findFirst():
Throws:
NullPointerException - if the element selected is null
As already discussed, the API designers do not assume that the developer wants to treat null values and absent values the same way.
If you still want to do that, you may do it explicitly by applying the sequence
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
to the stream. The result will be an empty optional in both cases, if there is no first element or if the first element is null. So in your case, you may use
String firstString = strings.stream()
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
.orElse(null);
to get a null value if the first element is either absent or null.
If you want to distinguish between these cases, you may simply omit the flatMap step:
Optional<String> firstString = strings.stream()
.map(Optional::ofNullable).findFirst().orElse(null);
System.out.println(firstString==null? "no such element":
firstString.orElse("first element is null"));
This is not much different to your updated question. You just have to replace "no such element" with "StringWhenListIsEmpty" and "first element is null" with null. But if you don’t like conditionals, you can achieve it also like:
String firstString = strings.stream()
.map(Optional::ofNullable).findFirst()
.orElseGet(()->Optional.of("StringWhenListIsEmpty"))
.orElse(null);
Now, firstString will be null if an element exists but is null and it will be "StringWhenListIsEmpty" when no element exists.
You can use java.util.Objects.nonNull to filter the list before find
something like
list.stream().filter(Objects::nonNull).findFirst();
The following code replaces findFirst() with limit(1) and replaces orElse() with reduce():
String firstString = strings.
stream().
limit(1).
reduce("StringWhenListIsEmpty", (first, second) -> second);
limit() allows only 1 element to reach reduce. The BinaryOperator passed to reduce returns that 1 element or else "StringWhenListIsEmpty" if no elements reach the reduce.
The beauty of this solution is that Optional isn't allocated and the BinaryOperator lambda isn't going to allocate anything.
Optional is supposed to be a "value" type. (read the fine print in javadoc:) JVM could even replace all Optional<Foo> with just Foo, removing all boxing and unboxing costs. A null Foo means an empty Optional<Foo>.
It is a possible design to allow Optional with null value, without adding a boolean flag - just add a sentinel object. (could even use this as sentinel; see Throwable.cause)
The decision that Optional cannot wrap null is not based on runtime cost. This was a hugely contended issue and you need to dig the mailing lists. The decision is not convincing to everybody.
In any case, since Optional cannot wrap null value, it pushes us in a corner in cases like findFirst. They must have reasoned that null values are very rare (it was even considered that Stream should bar null values), therefore it is more convenient to throw exception on null values instead of on empty streams.
A workaround is to box null, e.g.
class Box<T>
static Box<T> of(T value){ .. }
Optional<Box<String>> first = stream.map(Box::of).findFirst();
(They say the solution to every OOP problem is to introduce another type :)

Optional<T> does not handle null elements

As I experimented Optional<T> does not handle null elements, so in the following example it throws a NullPointerException in the last statement:
List<String> data = Arrays.asList("Foo", null, "Bar");
data.stream().findFirst().ifPresent(System.out::println);
data.stream().skip(1).findFirst().ifPresent(System.out::println);
So, I still have to explicitly deal with null and filter non-null elements, such as:
data.stream()
.filter(item -> item != null)
.skip(1)
.findFirst()
.ifPresent(System.out::println);
Is there any alternative that avoids dealing explicitly with null as: item != null
You can use .filter(Objects::nonNull) using the method Objects.nonNull(…) added for this purpose.
There is no way to avoid explicit filtering, unless you avoid having nulls in your source list in the first place.
Note that it would be strange if the Optional handled the null in this case as it would yield an empty optional which had the semantic of “there is no first element” which implies “the stream was empty” which is just wrong.
Dealing with nulls explicitly is the cleanest solution here as it also allows you to explicitly tell whether you want .filter(Objects::nonNull).skip(1), .skip(1).filter(Objects::nonNull)…
…or .map(s->s==null? "null-replacement": s).findFirst()
It really depends on what you want to do. If you want to treat null as a valid value, the answer is different than if you want to skip nulls.
If you want to keep "nulls" in your stream:
List<String> data = Arrays.asList("Foo", null, "Bar");
data.stream().map(Optional::ofNullable).findFirst().flatMap(Function.identity()).ifPresent(System.out::println); ;
data.stream().map(Optional::ofNullable).skip(1).findFirst().flatMap(Function.identity()).ifPresent(System.out::println);
If you want to remove nulls from your stream, use data.stream().filter(Objects::nonNull) to filter it out (or as you stated o -> o != null, whatever you prefer.

What's the difference when assigning a value to a field in square brackets LINQ?

I have seen when coding in LINQ that when a value is assigned to a field sometimes is in this way Table["Field"] and any others like this Table.Field but can somebody explain me what's the difference please?
For example when modifying a field:
var ttAbccode_xRow =
(from ttAbccode_Row in ds.ABCCode select ttAbccode_Row).FirstOrDefault();
if (ttAbccode_xRow != null) {
ttAbccode_xRow["PI"] = 3.1416;
}
or
if (ttAbccode_xRow != null) {
ttAbccode_xRow.PI = 3.1416;
}
Accessing field via indexer (square brackets) returns object data type. That means that your compiler cannot detect data types incompatibility. You could assing for example string value (eg. "abcd") and you won't get error at design time, but as late as at runtime.
Second method (if available in your result set) is much more safe. Your property will have proper data type hence compiler will detect data types incompatibility at design time.
If I had both access methods available I would always prefer second one. It is less error prone.

Resources