I have a list of strings, and want to use a single line of Linq to return the list's unique value (if there is one) or null, otherwise. In other words:
["a","a","a","a","a"] returns "a"
["a"] returns "a"
["a","a","a","a","b"] returns null
["a","b","c"] returns null
[] returns null
I assume I would use IEnumerable.Distinct() to collapse the list to its unique values, but I don't know how to do the "single or null" (SingleOrDefault() throws an exception if there's more than one item; FirstOrDefault() will always return the first item, and won't return null if there's two or more like I want.)
Any ideas? I'm just really curious if there's a simple way to do this in a single line that I'm overlooking. Bonus points if you don't have to write an extension method to make it work. Thanks!
col.Distinct().Count() == 1? col.First() : null;
Would this do?
col.Distinct().Count() > 1 ? null : col.Distinct().First();
Updated to handle empty collection
col.Count() == 0 ? null : col.Distinct().Count() > 1 ? null : col.Distinct().First();
Related
I am doing the following:
List<Objects> filtered = objects.stream()
.filter(o -> source.equals(o.getSource()) && date.equals(o.getDate()) && id.equals(o.getId()))
.collect(Collectors.toList());
where both date and id could possibiliy be null, as the are coming from method parameters.
How can I ignore them if null, without wrapping the above code in an if statement tp check 'id' and 'date' for null values ? I want to do it inside the filter.
Edit : To make it more clear, i want the filter to act only on the non-null values, i.e if date is non-null and id is null, then filter only on date and ignore id, and so on..
Thanks
An additional option is to do the null checks in the predicate:
.filter(o -> source.equals(o.getSource())
&& (null == date || date.equals(o.getDate()))
&& (null == id || id.equals(o.getId())))
You could use the static method Objects::equals. Chances are that this method is designed for just this:
List<Objects> filtered = objects.stream()
.filter(o -> Objects.equals(source, o.getSource()) && Objects.equals(date, o.getDate()) && Objects.equals(id, o.getId()))
.collect(Collectors.toList());
Note: as Scratte mentioned in the comments, this may not filter out objects for which getDate() returns null, if date is also null. Same goes for id. If that's the case, then the abovementioned code snippet does not comply. In that case, then we have to explicitly filter for non-null dates and ids:
.filter(o -> Objects.nonNull(o.getId()) && Objects.nonNull(o.getDate()))
Update
If you want to skip the comparison for getDate() if date is null (and same for id), then you could check first for null, just like in ernest_k's answer.
You could easily build a small method for it:
public static boolean nullOrEquals(Object baseObject, Object compareObject) {
return baseObject == null || Objects.equals(baseObject, compareObject);
}
.filter(o -> Objects.equals(source, o.getSource())
&& nullOrEquals(date, o.getDate())
&& nullOrEquals(id, o.getId()))
Here's an Ideone example.
I have this table Line with a DEL_IND column. The possible values are Y or null
Im using OBIP, and there is a parameter requirement that allows selection of null or Y.
OBIP do not allow blank in their 'fixed value' menu.
I've tried to enter 'List of Values' in OBIP for No to be '' (empty string), but it doesnt seem to work.
LINE.DEL_IND = :P_DELETION_FLAG << i need to pass the value null for this clause
How do I pass null value selection into the query?
Even if you find the way to pass NULL, this:
WHERE LINE.DEL_IND = :P_DELETION_FLAG
won't work properly. If :P_DELETION_FLAG is NULL, query should look like this:
WHERE (LINE.DEL_IND = :P_DELETION_FLAG or :P_DELETION_FLAG IS NULL)
because
WHERE LINE.DEL_IND = NULL
is invalid; should be
WHERE LINE.DEL_IND IS NULL (or IS NOT NULL)
I am working on LINQ query with Left-Join and groupBy, so I have list of questions which may or may not have answer collections. I want all the question group by question and their answer list, if it is null then don't want to add.
My current solution works fine but it still add a list with null where no answer is there hence giving me wrong result on Answer count()
var dhd = (from question in Context.Questions
join answer in Context.Answers on question.Id equals answer.QuestionId into ps
from answerDetail in ps.DefaultIfEmpty()
group answerDetail by question into grouped
select new
{
Question = grouped.Key,
Answer = grouped.ToList(),
//Answer = grouped.ToList() == null ? "(No Answer)" : grouped.Select(x => x.Value).FirstOrDefault(),
TotalAnswerCount = grouped.Count()
}).ToList();
I have tried following script in above code and it throw null exception
Answer = grouped.ToList() == null ? "(No Answer)" : grouped.Select(x => x.Value).FirstOrDefault(),
When you call ps.DefaultIfEmpty() it's making a list with null for non-matching element. If you want to get just null instead of a list with a null element, then try this code:
Answer = grouped.FirstOrDefault() == null ? null : grouped.ToList(),
If there's no match, then Answer is null, otherwise you get a list.
I think issue occur because of type so try this one:
Answer = grouped.ToList() == null ? null : grouped.Select(x => x.Value).FirstOrDefault(),
When using sum with lambda in Linq to SQL using the following code:
int query = (from f in odc.RDetails
where f.ticketID == int.Parse(ticket.ToString())
select f).Sum(x => x.Rate);
I get the following error:
The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type.
. You have to make sure x.Rate is an int, and not an int? (an int that accepts null as a value).
. If the query has no elements, .Sum won't do anything and will return null. Choose a default value, let's say 0.
var query = from f in odc.RDetails
where f.ticketID == int.Parse(ticket.ToString())
select f;
int result = query.Any()
? query.Sum(x => x.Rate ?? 0) // use the ?? if x.Rate is an "int?".
: 0; // default value you can choose.
I would break the int.Parse(ticket.ToString()) onto its own line to isolate that parse from the Linq for debugging.
We don't know whether that is throwing the exception or if one of the RDetails.Rate values is null. Is it indeed a Nullable<int>?
If RDetails.Rate is a Nullable<int>, then you could ...Sum(x => x.Rate ?? 0) and avoid the exception.
I have a set DataRows and I want to check if any of the fields in any of those rows has a NULL value in it. I came up with this below, but I'm not sure because I'm nesting an ALL.
result.AsEnumerable().AsQueryable().All(o => o.ItemArray.All(i=>i == DBNull.Value))
Hard to tell because I can't put a "watch" in lambdas.
Actually you need to use Any (in your code you will return true if All values are null) and AsQueryable() is useless in this case.
bool nullFound = result.AsEnumerable()
.Any(o => o.ItemArray.Any(i=>i == DBNull.Value || i == null));
Then, If you need a list of all rows with some value null, just do the following:
var rowsWithNulls = result.AsEnumerable()
.Where(o => o.ItemArray.Any(i=>i == DBNull.Value || i == null))
.ToList();
P.S.
I also added a null check to be more safe, but if you are sure to have only DBNull.Value, you can remove it.
Not sure if this is the correct answer. I'm also rather new to Linq, but i believe you can do something like this;
result.AsEnumerable().AsQueryable().SingleOrDefault(o => o.ItemArray.All(i=>i == DBNull.Value))
This will return an list of items or null if there aren't any. Not sure if you can also nest it, but don't see why it wouldn't be possible