In Java I can do this:
List<String> stringList = getRandomStrings(100_000, 1000);
IntSummaryStatistics stats =
stringList.stream()
.filter(Objects::nonNull)
.mapToInt(String::length)
.summaryStatistics();
System.out.println(stats);
The output is:
IntSummaryStatistics{count=100000, sum=49868013, min=0, average=498.680130, max=999}
Does linq have the same functionality? Or do I have to calculate everything seperately?
Java does this in one go, and it looks like in C# you have to calculate all the constituents Average()
, Count()
, Sum()
, Min()
and Max()
separately.
I'm not aware of anything built into .NET that does the equivalent, but you can easily implement it yourself using Aggregate
from LINQ. This meets your requirement of only enumerating the source collection once.
var ints = new List<int>() { 1, 2, 3, 4, 677, 8 };
var summary = ints.Aggregate(
seed: (
count: 0,
sum: 0,
min: int.MaxValue,
max: int.MinValue),
func: (acc, x) => (
count: acc.count + 1,
sum: acc.sum + x,
min: Math.Min(acc.min, x),
max: Math.Max(acc.max, x)),
resultSelector: acc => (
acc.count,
acc.sum,
acc.min,
acc.max,
avg: (double)acc.sum / acc.count));
Console.WriteLine(
$"count = {summary.count}, " +
$"sum = {summary.sum}, " +
$"min = {summary.min}, " +
$"max = {summary.max}, " +
$"average = {summary.avg}");
If your collection is very large and you want to parallelize its processing, you can use this overload:
var summary = ints.AsParallel().Aggregate(
seed: (
count: 0,
sum: 0,
min: int.MaxValue,
max: int.MinValue),
updateAccumulatorFunc: (acc, x) => (
count: acc.count + 1,
sum: acc.sum + x,
min: Math.Min(acc.min, x),
max: Math.Max(acc.max, x)),
combineAccumulatorsFunc: (acc1, acc2) => (
count: acc1.count + acc2.count,
sum: acc1.sum + acc2.sum,
min: Math.Min(acc1.min, acc2.min),
max: Math.Max(acc1.max, acc2.max)),
resultSelector: acc => (
acc.count,
acc.sum,
acc.min,
acc.max,
avg: (double)acc.sum / acc.count));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With