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.
Related
This is my first question on this site. I am practicing on a problem on Hackerrank that asks to find numbers "Between two Sets". Given two arrays of integers, I must find the number(s) that fit the following two criteria:
1) The elements in the first array must all be factors of the number(s)
2) The number(s) must factor into all elements of the second array
I know that I need to find all common multiples of every element in the first array, but those multiples need to be less than or equal to the minimum value of the second array. I first sort the first array then find all the multiples of ONLY the largest number in the first array (again, up to a max of the second array's minimum) and store those multiples in a list. Then, I move on to the second largest element in the first array and test it against the array of existing multiples. All elements in the list of existing multiples that isn't also a multiple of the second largest element of the first array is removed. I then test the third largest value of the first array, all the way to the minimum value. The list of existing multiples should be getting trimmed as I iterate through the first array in descending order. I've written a solution which passes only 5 out of the 9 test cases on the site, see code below. My task was to edit the getTotalX function and I created the getCommonMultiples function myself as a helper. I did not create nor edit the main function. I am not sure why I am not passing the other 4 test cases as I can't see what any of the test cases are.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution {
/*
* Complete the getTotalX function below.
*/
static int getTotalX(int[] a, int[] b) {
//get minimum value of second array
int b_min = b.Min();
//create List to hold multiples
List<int> multiples = getCommonMultiples(a, b_min);
//create List to hold number of ints which are in solution
List<int> solutions = new List<int>();
foreach(int x in multiples)
{
foreach(int y in b)
{
if (y % x == 0 && !solutions.Contains(x))
{
solutions.Add(x);
}
else
{
break;
}
}
}
return solutions.Count;
}
static List<int> getCommonMultiples(int[] array, int max)
{
//make sure array is sorted
Array.Sort(array);
int x = array.Length - 1; //x will be the last # in array -- the max
int y = 1;
//find all multiples of largest number first and store in a list
int z = array[x] * y;
List<int> commonMultiples = new List<int>();
while(z <= max)
{
commonMultiples.Add(z);
y++;
z = array[x] * y;
}
//all multiples of largest number are now added to the list
//go through the smaller numbers in query array
//only keep elements in list if they are also multiples of smaller
//numbers
int xx = array.Length - 2;
for(int a = array[xx]; xx >= 0; xx--)
{
foreach(int b in commonMultiples.ToList())
{
if (b % a != 0)
{
commonMultiples.Remove(b);
}
else
{
continue;
}
}
}
return commonMultiples;
}
static void Main(string[] args) {
TextWriter tw = new StreamWriter(#System.Environment.GetEnvironmentVariable("OUTPUT_PATH"), true);
string[] nm = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(nm[0]);
int m = Convert.ToInt32(nm[1]);
int[] a = Array.ConvertAll(Console.ReadLine().Split(' '), aTemp => Convert.ToInt32(aTemp))
;
int[] b = Array.ConvertAll(Console.ReadLine().Split(' '), bTemp => Convert.ToInt32(bTemp))
;
int total = getTotalX(a, b);
tw.WriteLine(total);
tw.Flush();
tw.Close();
}
}
Again, I can't see the test cases so I do not know what exactly the issue is. I went through the code line by line and can't find any OutOfBoundExceptions or things of that sort so it has to be a logic issue. Thanks for the help!
A typical sample involves 3 lines of input. The first line has 2 integers which gives the length of the first array and the second array, respectively. The second line will give the integers in the first array. The third line will give the integers in the second array. The output needs to be the total number of integers "in between" the two arrays. It will looks like this:
Sample Input
2 3
2 4
16 32 96
Sample Output
3
Explanation: 2 and 4 divide evenly into 4, 8, 12 and 16.
4, 8 and 16 divide evenly into 16, 32, 96.
4, 8 and 16 are the only three numbers for which each element of the first array is a factor and each is a factor of all elements of the second array.
I see two issues with the code you posted.
Firstly, as #Hans Kesting pointed out, a = array[xx] is not being updated each time in the for loop. Since the variable a is only used in one spot, I recommend just replacing that use with array[xx] and be done with it as follows:
for(int xx = array.Length - 2; xx >= 0; xx--)
{
foreach(int b in commonMultiples.ToList())
{
if (b % array[xx] != 0)
{
commonMultiples.Remove(b);
For your understanding of for loops: to properly increment a each time you'd write the for loop like this:
for(int xx = array.Length - 2, a = array[xx]; xx >= 0; xx--, a = array[xx])
The first part of the for loop (up until ;) is the initialization stage which is only called before the entering the loop the first time. The second part is the while condition that is checked before each time through loop (including the first) and if at any time it evaluates to false, the loop is broken (stopped). The third part is the increment stage that is called only after each successful loop.
Because of that in order to keep a up to date in the for loop head, it must appear twice.
Secondly, your solutions in getTotalX is additive, meaning that each multiple that works for each value in array b is added as a solution even if it doesn't fit the other values in b. To get it to work the way that you want, we have to use a Remove loop, rather than an Add loop.
List<int> multiples = getCommonMultiples(a, b_min);
//create List to hold number of ints which are in solution
List<int> solutions = multiples.ToList();
foreach(int x in multiples)
{
foreach(int y in b)
{
if (y % x != 0)
{
solutions.Remove(x);
break;
}
}
}
You could also use LINQ to perform an additive solution where it takes into account All members of b:
//create List to hold number of ints which are in solution
List<int> solutions = multiples.Where((x) => b.All((y) => y % x == 0)).ToList();
I'm trying to learn how to use lambdas and in this code I'm trying to get index of some value that is available in the array, but it just return for values 5 and 8 fine and for the other values it keeps throwing IndexOutOfRangeException!
int[] nums = { 2, 3, 5, 8, 9 };
int rez = nums.Where(i => nums[i] == 2).FirstOrDefault();
Console.WriteLine(rez);
Please tell me what would happen to "index" return value while trying to retrieving it?
Thanks in advance.
in your lambda expression (i => nums[i] == 2), i would represent the number itself not its index so nums[i] won't work.
You can simply do this using Array.IndexOf():
int rez = Array.IndexOf(nums, 2);
Or if you insist on doing it by Linq (not recommended):
int rez = nums.Select((x, i) => new {x, i}).FirstOrDefault(a => a.x == 2).i;
i in your lambda is an element (and not the index) of the nums array.
So, first i is equal to 2 (the first element of nums). nums[2] != 2, so it goes further.
i is equal to 3 (the second element of nums). nums[3] != 2, so it goes further.
Then, i is equal to 5 (the third element of nums).nums[5] != 2 but your array has 5 elements and the last element has index 4 (because index is zero based). So, when you tried to access nums[5] you get an IndexOutOfRangeException expectedly.
There seems to be no e.TakeWhile(predicate, atLeastNElements) overload. Is there a convenient way to express TakeWhile, however, take at least N elements if there are >= N elements available.?
Edit: the best I came up with in my head is to capture an int in TakeWhile's predicate and reduce it by one each call while returning true. The actual predicate is used only after the counter is down to zero.
You can use an overload to TakeWhile with the index of the current element:
var e = new [] { 1, 2, 3, 4, 5 };
var n = 3; // at least n
e.TakeWhile((element, index) => index < n || predicate(element));
I have following code snippet in c#
static void Main()
{
var numbers = new[] { 1, 2, 3, 4, 5, 6 };
var ngt5 = numbers.Where(n => n > 5);
var n = ngt5.First().ToString();
Console.WriteLine(n, numbers);
}
When I am compiling the above code I am getting following error
A local variable named 'n' cannot be declared in this scope
Your problem is here:
// Within your lambda you have an 'n'.
var ngt5 = numbers.Where(n => n > 5);
// And within the outer scope you also have an 'n'.
var n = ngt5.First().ToString();
To understand why this is a problem, consider the following code:
int n = 1000;
var evens = Enumerable.Range(1, 1000).Where(n => n % 2 == 0);
The expression n % 2 == 0 above is ambiguous: which n are we talking about? If we're talking about the outer n, then n % 2 == 0 is always true since n is just 1000 (and therefore evens will comprise all numbers from 1 to 1000). On the other hand, if we're talking about the inner n, then n % 2 == 0 will only hold true for even values of n (and evens will be 2, 4, 6, ... 1000).
The important point to realize is that variables declared outside the lambda are accessible from within the lambda's scope.
int n = 0;
Action incrementN = () => n++; // accessing an outer variable
incrementN();
Console.WriteLine(n); // outputs '1'
This is why the ambiguity exists, and why it is therefore not allowed.
The solution is simply to pick a different variable name for your lambda; e.g.:
var ngt5 = numbers.Where(x => x > 5);
Your problem is that you assume that closures are first class functions in C#, which is not the case and I wish it was the case.
You can't treat scope of C# closure as isolated function scope.
You can't return complicated Linq expression outside of current scope.
JavaScript allows this ambiguity, which allows to write closures without any limit, which makes closures first class functions of JavaScript.
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