Aggregate lambda expressions - c#

int sum0 = 0;
for (int i = 0; i < 10; i++)
{
sum0 += i;
}
int sum1 = Enumerable.Range(0, 10).Sum();
int sum2 = Enumerable.Range(0, 10).Aggregate((x, y) => x + y);
int sum3 = Enumerable.Range(0, 10).Aggregate(0, (x, y) => x + y);
All of the above 4 expressions are doing the same thing: find sum from 0 to 10. I understand the calculation of sum0 and sum1. But what are sum2 and sum3? Why the lambda uses two parameters (x, y) here?

Expanding on bdukes' answer, the lambda takes
( x = [value of last lambda expression], y = [next value] ) => x+y
and sum3 allows you to set the initial x value.

The Enumerable.Aggregate method expects a function that takes the current value of the aggregation and a value from the enumeration. The overload for sum3 also provides a starting value for the aggregation.

X is holding the current total, Y is being added to it for each element.
Foreach(y)
X = X + Y;

The Aggregate extension methods take a function (Func<T1,T2,TResult>) that calculates an aggregate..
The function specified for sum2 is one that adds x to y, for every supplied x and y (that is it sums all the items in the enumeration).
The additional parameter for sum3 is an accumulator - a value that is to be added for each operation - as this is 0, it is essentially summing up all the items in the enumeration without any additional values.

sum2 uses a custom function x + y to aggregate each element of the list. The aggregation starts with the default value for an integer 0 and adds the first element to it. It then takes that value and adds the next element, and so on, until it runs out of elements. It then returns the final figure.
sum3 does exactly the same as sum2 but it also explicitly starts the aggregation with a specific value of 0.
Semantically all three are the same - as presented here - but by varying the aggregation function and the initial starting value you can generate all sorts of custom aggregations.
Another way of looking at it is that .Sum() is simply short-hand for .Aggregate(0, (x, y) => x + y);.

x is the variable that "accumulates" the values so its value is
step 1) 1
step 2) 3
step 3) 6
step 4) 10
and so on...
the 0 in the sum3 is the starting value :) (which is redundant since 0 is the default value for int)

The parameter x holds the aggregation, and y is the next enumeration item.
string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words.
string[] words = sentence.Split(' ');
// Prepend each word to the beginning of the
// new sentence to reverse the word order.
string reversed = words.Aggregate((workingSentence, next) =>
next + " " + workingSentence);
Console.WriteLine(reversed);
// This code produces the following output:
//
// dog lazy the over jumps fox brown quick the
from http://msdn.microsoft.com/en-us/library/bb548651.aspx

Related

How to increase value of an integer higher than 1 in one command?

You could write example++; multiple times in your loop if you need to increase by more than 1, but what if i need to increase by like 100? Is there a way to make it multiply or increase by more than 1? (other than multiplying it in Console.WriteLine)
Per the comment from peter:
example += 100;
Means the same as
example = example + 100;
This is called Compound Assignment and there are many operators that do their work in this way, such as
example -= 100;
example *= 100;
For the full list, refer to the MSDN linked above
Any assignment in c# returns the assigned value so it can be used as part of a bigger statement. The += is no different, and this will print "x incremented is 101":
int x = 1;
Console.WriteLine("x incremented is " + (x+= 100));
The only thing worthy of note is that ++ exists in two forms, either x++ or ++x - the first form returns the value of x before it was incremented, the second form returns the value after.
int x = 1;
Console.WriteLine("x incremented is " + (x++)); //x is now 2 but the message says it is 1
Console.WriteLine("x incremented is " + (++x)); //x is now 3 and the message says it is 3
+= only returns the value after increment. There is no form that returns x before you add 100 to it
The simplest solution to increase value of example by an amount x would be example=example+x. This is more legible, however you can use the short form example+=x.

How to subtract x from every number in a listbox

So I have a list box of numbers and I want to subtract an integer from every single number of a list box. Here is an example:
1
2
3
4
5
I want to get the absolute value of the difference
Math.Abs(2 - 1)
Math.Abs(2 - 2)
Math.Abs(2 - 3)
Math.Abs(2 - 4)
Math.Abs(2 - 5)
And put them in a list box.
I've tried:
while (i < listBox1.Items.Count)
{
result -= Convert.ToInt32(listBox1.Items[i++]);
int result1 = Convert.ToInt32(result)
int sub = Math.abs(result1)
}
Would this work :
I am using Select(x => {return x;}) notation of linq to do an operation on the array element, and return a value. In this case, the operation is Math.abs of each element of the array and a given number. _absDiffs will be an IEnumerable<int>, which you could call .ToArray() on to turn it into int[].
int[] _nums = {1,2,3,4,5};
int _number = 2;
var _absDiffs = _nums.Select(num=> { return Math.abs(_number - num);});

What is the difference between these two pieces of code?

int[] div = new int[] {2,3,5};
IEnumerable<int> seq = new int[] {10,15,20,25,30};
int x;
for (int i=0; i<div.Length; i++){
x = div[i];
seq = seq.Where( s=> s%x ==0);
}
seq = seq.ToList();
AND
int[] div = new int[] {2,3,5};
IEnumerable<int> seq = new int[] {10,15,20,25,30};
for (int i=0; i<div.Length; i++){
int y = div[i];
seq = seq.Where( s=> s%y ==0);
}
seq = seq.ToList();
The first seq's final value is 10,15,20,25,30 and the second one's is 30.
I'm a little confused about the difference between int x;
and int y = div[i]; . Can someone explain this to me?
Thanks!
Invoking seq = seq.Where( s=> s%x ==0); does not iterate over elements. It only creates an IEnumarable encapsulating the iteration, that can be iterated in fututre.
So if you declare your x variable before the loop, the lambda, that you passed in Where() uses the same variable. Since you are changing its value in a loop, eventually only the last one will be actually used.
Instead of expression like:
seq.Where( s=> s % 2 == 0).Where( s=> s % 3 == 0).Where( s=> s % 5 == 0);
you get:
seq.Where( s=> s % 5 == 0).Where( s=> s % 5 == 0).Where( s=> s % 5 == 0);
The result is different because you are using lambda expression in the LINQ's Where() parameter. The actual execution of the all lambdas in Where()'s is performed on the very last row of both examples - the line where you perform .ToList(). Have a look at the Variable Scope in Lambda Expressions
The difference in the examples is how you initialize x/y.
In the first example there is only one memory slot for the variable x regardless of number of iterations of the foreach. The x always points to the same spot in the memory. Therefore there is only one value of the x on the last row and it is equal to the div[2].
In the second example there is separate memory slot created for y in each iteration of the loop. As the program evaluates, the address where y points to is changed in every iteration of the foreach. You might imagine it as there are multiple y variables like y_1, y_2,... Hence when evaluating the actual lambdas in Where()s the value of the y is different in every one of them.

Most evenly distribute letters of the alphabet across sequence

I'm wondering if there is a sweet way I can do this in LINQ or something but I'm trying to most evenly distribute the letters of the alphabet across X parts where X is a whole number > 0 && <= 26. For example here might be some possible outputs.
X = 1 : 1 partition of 26
X = 2 : 2 partitions of 13
X = 3 : 2
partitions of 9 and one partition of 8
etc....
Ultimately I don't want to have any partitions that didn't end up getting at least one and I'm aiming to have them achieve the most even distribution that the range of difference between partition sizes is as small as posssible.
This is the code I tried orginally:
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
int pieces = (int)Math.Round((double)alphabet.Count() / numberOfParts);
for (int i = 0; i < numberOfParts.Count; ++i) {
char[] subset = i == numberOfParts.Count - 1 ? alphabet.Skip(i * pieces).ToArray()
: alphabet.Skip(i * pieces).Take(pieces).ToArray();
... // more code following
This seemed to be working fine at first but I realized in testing that there is a problem when X is 10. Based on this logic I'm getting 8 groups of 3 and one group of 2, leaving the 10th group 0 which is no good as I'm going for the most even distribution.
The most ideal distribution for 10 in this case would be 6 groupings of 3 and 4 groupings of 2. Any thoughts on how this might be implemented?
In general, the easiest way to implement the logic is using the modulo operator, %. Get familiar with this operator; it's very useful for the situations where it helps. There are a number of ways to write the actual code to do the distribution of letters, using arrays or not as you wish etc., but this short expression should give you an idea:
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".IndexOf(letter) % partitionCount
This expression gives the zero-based index of the partition in which to deposit an upper-case letter. The string is just shown for convenience, but could be an array or some other way of representing the alphabet. You could loop over the alphabet, using logic similar to the above to choose where to deposit each letter. Up to you would be where to put the logic: inside a loop, in a method, etc.
There's nothing magical about modular arithmetic; it just "wraps around" after the end of the set of usable numbers is reached. A simple context in which we've all encountered this is in division; the % operator is essentially just giving a division remainder. Now that you understand what the % operator is doing, you could easily write your own code to do the same thing, in any language.
Putting this all together, you could write a utility, class or extension method like this one--note the % to calculate the remainder, and that simple integer division discards it:
/// <summary>
/// Returns partition sized which are as close as possible to equal while using the indicated total size available, with any extra distributed to the front
/// </summary>
/// <param name="totalSize">The total number of elements to partition</param>
/// <param name="partitionCount">The number of partitions to size</param>
/// <param name="remainderAtFront">If true, any remainder will be distributed linearly starting at the beginning; if false, backwards from the end</param>
/// <returns>An int[] containing the partition sizes</returns>
public static int[] GetEqualizedPartitionSizes(int totalSize, int partitionCount, bool remainderAtFront = true)
{
if (totalSize < 1)
throw new ArgumentException("Cannot partition a non-positive number (" + totalSize + ")");
else if (partitionCount < 1)
throw new ArgumentException("Invalid partition count (" + partitionCount + ")");
else if (totalSize < partitionCount)
throw new ArgumentException("Cannot partition " + totalSize + " elements into " + partitionCount + " partitions");
int[] partitionSizes = new int[partitionCount];
int basePartitionSize = totalSize / partitionCount;
int remainder = totalSize % partitionCount;
int remainderPartitionSize = basePartitionSize + 1;
int x;
if (remainderAtFront)
{
for (x = 0; x < remainder; x++)
partitionSizes[x] = remainderPartitionSize;
for (x = remainder; x < partitionCount; x++)
partitionSizes[x] = basePartitionSize;
}
else
{
for (x = 0; x < partitionCount - remainder; x++)
partitionSizes[x] = basePartitionSize;
for (x = partitionCount - remainder; x < partitionCount; x++)
partitionSizes[x] = remainderPartitionSize;
}
return partitionSizes;
}
I feel like the simplest way to achieve this is to perform a round robin distribution on each letter. Cycle through each letter of the alphabet and add to it, then repeat. Have a running count that determines what letter you will be putting your item in, then when it hits >26, reset it back to 0!
What I did in one app I had to distribute things in groups was something like this
var numberOfPartitions = GetNumberOfPartitions();
var numberOfElements = GetNumberOfElements();
while (alphabet.Any())
{
var elementsInCurrentPartition = Math.Ceil((double)numberOfPartitions / numberOfElements)
for (int i = 0; i < elementsInCurrentPartition; i++)
{
//fill your partition one element at a time and remove the element from the alphabet
numberOfElements--;
}
numberOfPartitions--;
}
This won't give you the exact result you expected (i.e. ideal result for 10 partitions) but it's pretty close.
p.s. this isn't tested :)
A pseudocode algorithm I have now tested:
Double count = alphabet.Count()
Double exact = count / numberOfParts
Double last = 0.0
Do Until last >= count
Double next = last + exact
ranges.Add alphabet, from:=Round(last), to:=Round(next)
last = next
Loop
ranges.Add can ignore empty ranges :-)
Here is a LinqPad VB.NET implementation of this algorithm.
So a Linq version of this would be something like
Double count = alphabet.Count();
Double exact = count / numberOfParts;
var partitions = Enumerable.Range(0, numberOfParts + 1).Select(n => Round((Double)n * exact));
Here is a LinqPad VB.NET implementation using this Linq query.
(sorry for formatting, mobile)
First, you need something like a batch method:
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int groupSize)
{
var tempSource = source.Select(n => n);
while (tempSource.Any())
{
yield return tempSource.Take(groupSize);
tempSource = tempSource.Skip(groupSize);
}
}
Then, just call it like this:
var result = alphabet.Batch((int)Math.Ceiling(x / 26.0));

How to make this function process in constant time?

I need to find the n-th term of this infinite series: 1,2,2,3,3,3,4,4,4,4...
Can you give me a constant time function for this task?
int i = 1;
while(true)
{
if(i = n)
//do things and exit the loop
i++;
}
I think this isn`t going to be a constant time function...
Edit
After reading more comments, it appears I misunderstood the question.
If you want to find the item at nth position an array in constant time, then the answer is trivial: x[n], because array access is constant time. However, if for some reason you were using some container where access time is not constant (e.g. linked list), or did not want to look up value in the array, you'd have to use the arithmetic series formulas to find the answer.
Arithmetic series tells us that the position n of the ith unique item would be
n = i * (i - 1) / 2
So we just need to solve for i. Using quadratic formula, and discarding the nonsensical negative option, we get:
i = Math.Floor( (1 + Math.Sqrt(1 + 8 * n)) / 2)
Original Response
I'm assuming you're looking for the position of the nth unique term, because otherwise the problem is trivial.
Sounds like the first occurrence of the nth unique term should follow arithmetic series. I.e. the position of nth unique term would be:
n * (n - 1) / 2
Given my understanding of the problem, this is more of a math problem than a programming one.
If the problem is:
Given an infinite series that consists of 1 copy of 1, 2 copies of 2, 3 copies of 3... n copies of n, what is the kth value in this series?
Now the first clue when approaching this problem is that there are 1 + 2 + 3... + n values before the first occurance of n + 1. Specifically there are (sum of the first n numbers) values before n+1, or (n)(n-1)/2.
Now set (n)(n-1)/2 = k. Multiply out and rationalize to n^2 - n - 2k = 0. Solve using quadratic equation, you get n = (1 + sqrt(1+8k))/2. The floor of this gives you how many full copies of n there are before, and happily, given zero based indexing, the floor gives you the value at the kth point in the array.
That means your final answer in c# is
return (int) Math.Floor((1 + Math.Sqrt(1 + 8 * k)) / 2);
Given non zero based indexing,
return (int) Math.Floor((1 + Math.Sqrt(-7 + 8 * k)) / 2);
public static long Foo(long index)
{
if (index < 0)
{
throw new IndexOutOfRangeException();
}
long nowNum = 0;
long nowIndex = 0;
do
{
nowIndex += nowNum;
nowNum++;
} while (nowIndex < index);
return nowNum;
}

Categories