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));
Related
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.
I am having problem while trying to get First and Second Record (not second highest/lowest integer) Index from a sorted List. Lets say that list consists of three records that in order are like this: 0, 0, 1.
I tried like this:
int FirstNumberIndex = MyList.IndexOf(MyList.OrderBy(item => item).Take(1).ToArray()[0]); //returns first record index, true
int SecondNumberIndex = MyList.IndexOf(MyList.OrderBy(item => item).Take(2).ToArray()[1]); //doesn't seem to work
As I explained, I am trying to get the indexes of first two zeros (they are not necessarily in ascending order before the sort) and not of zero and 1.
So if there was a list {0, 2, 4, 0} I need to get Indexes 0 and 3. But this may apply to any number that is smallest and repeats itself in the List.
However, it must also work when the smallest value does not repeat itself.
SecondNumberIndex is set to 0 because
MyList.OrderBy(item => item).Take(2).ToArray()[1] == 0
then you get
MyList.IndexOf(0)
that finds the first occurence of 0. 0 is equal to every other 0. So every time you ask for IndexOf(0), the very first 0 on the list gets found.
You can get what you want by using that sort of approach:
int FirstNumberIndex = MyList.IndexOf(0); //returns first record index, true
int SecondNumberIndex = MyList.IndexOf(0, FirstNumberIndex + 1 ); //will start search next to last ocurrence
From your code I guess you confuse some kind of "instance equality" with regular "equality".
Int is a simple type, IndexOf will not search for ocurrence of your specific instance of 0.
Keep in mind that this code, even if we will move in our thoughts to actual objects:
MyList.OrderBy(item => item).Take(2).ToArray()[1]
will not necessarily return equal objects in their original relative order from the input list.
EDIT
This cannot be adopted for general case, for getting indexes of ordered values from the original, unordered list.
If you are searching for indexes of any number of equal values, then setting bigger and bigger offset for the second parameter of IndexOf is OK.
But, let's consider a case when there are no duplicates. Such approach will work only when the input list is actually ordered ;)
You can preprocess your input list to have pairs (value = list[i],idx = i), then sort that pairs by value and then iterate over sorted pairs and print idx-es
You, probably, are asking about something like this:
var list = new List<int>{0,0,1};
var result = list.Select((val,i)=> new {value = val, idx = i}).Where(x=>x.value == 0);
foreach(var r in result) //anonymous type enumeration
Console.WriteLine(r.idx);
You can try user FindIndex.
var MyList = new List<int>() {3, 5, 1, 2, 4};
int firsIndex = MyList.FindIndex(a => a == MyList.OrderBy(item => item).Take(1).ToArray()[0]);
int secondIndex = MyList.FindIndex(a => a == MyList.OrderBy(item => item).Take(2).ToArray()[1]);
You could calculate the offset of the first occurrence, then use IndexOf on the list after skipping the offset.
int offset = ints.IndexOf(0) + 1;
int secondIndex = ints.Skip(offset).ToList().IndexOf(0) + offset;
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.
I saw the article : C# find highest array value and index
I have another question is : How to find the other index if there exists duplicate value?
Assume that array is
int[] anArray = { 1, 5, 2, 7 , 7 , 3};
int maxValue = anArray.Max();
int maxIndex = anArray.ToList().IndexOf(maxValue);
How to find the other index if I use the method in this article?
Your question is "how do I find the other index" but it should be "how do I find all other indexes" because there might be multiple.
int[] anArray = { 1, 5, 2, 7, 7, 3 };
int maxValue = anArray.Max();
int maxIndexes =
anArray
.Select((x, i) => new { x, i }) //add indexes to sequence
.Where(x => x == maxValue) //filter on maxValue
.Select(x => x.i) //only select index
.ToList(); //ToList is optional
If you only want the last one, or you are sure that there is at most one such indexes, just end the query with .Last() or similar.
This answer your question. Use LastIndexOf() will find the last index of the value you specify ;)
This way you will get the last index and the last index of this value:
int maxValue = anArray.Max()
int index = anArray.ToList().LastIndexOf(maxValue);
Refer to accepted answer of Get indexes of all matching values from list using Linq
All of the LINQ methods are carefully designed to only ever iterate the source sequence once (when they are iterated once). Therefore we use Enumerable.Range expressions from LINQ to loop
int[] anArray = { 1, 5, 2, 7 , 7 , 3};
int maxValue = anArray.Max();
var result = Enumerable.Range(0, anArray.Count())
.Where(i => anArray[i] == maxValue)
.ToList();
Extra info : Enumerable.Range automatically excludes the highest index, anArray.Count().
How to get the closest number from a List<int> with LINQ?
For example:
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(5);
numbers.Add(7);
numbers.Add(10)
I need to find the closest value in the list to number 9. In this case 10.
How can I do this with LINQ?
If you use LINQ to Objects and the list is long, I would use:
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
int closest = list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-number) ? x : y);
This method is slightly more complex than the solution that Anthony Pegram suggested, but it has as advantage that you don't have to sort the list first. This means that you have a time complexity of O(n) instead of O(n*log(n)) and a memory usage of O(1) instead of O(n).
If you want to use LINQ to perform this task, you can do it like below.
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
// find closest to number
int closest = list.OrderBy(item => Math.Abs(number - item)).First();
The solutions above are all O(N) at best.
If you have a big list and you perform this closest-element query multiple times, it would be more performant to sort the list first ( O(NlogN) ) and then use List<T>.BinarySearch for each query. The performance for k queries is O( (k+N)logN ), in comparison to O(kN) of the previous method.
These days there also exist a nice and simple option:
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
int min = list.Min(i => (Math.Abs(number - i), i)).i;
You could you the binary search. It is the build in method in c# that will help you search for the number closest. Here example: https://msdn.microsoft.com/en-us/library/y15ef976(v=vs.110).aspx
Use this get nearest lower or Higher based on condition You used.
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
var closest = list.Where(numbers => numbers > number).First();
Console.WriteLine(closest);
Console.ReadLine();