trying to skip and jump elements in a list
-
brain fart here :( how do you convert this to link
for (int i = 5; i < Count; i+=7) { MyList.Add(this[i]); }
What is "this"?
IQueryable list = (from x in this
select x).Skip(5).Take(5);
I know the language. I've read a book. - _Madmatt
-
brain fart here :( how do you convert this to link
for (int i = 5; i < Count; i+=7) { MyList.Add(this[i]); }
I don't think there is a direct way, but here is a workaround: Create a ValidationFunction( or a predicate or...) and use it for a where clause or a TakeWhile or... something like this for your example: I created a dummy class named... well Abs (original wright?)
public class Abs: IComparable
{
public string Name { get; set; }public int CompareTo(Abs other) { return this.Name.CompareTo(other.Name); } }
I populated a list of 100 Abs objects and sorted them:
for (int i = 0; i < 100; i++) { av = new Abs { Name = "Dap" + i.ToString() }; abses.Add(av); } abses.Sort();
created the ValidationFunction to match your for loop criteria:
private bool ValidIndex(Abs ab) { int index = abses.BinarySearch(ab); //can use abses.IndexOf(ab) if the class does bot implement Icomaparable //or if there is no custom IComparer provided return ((index > 0) && (index == 5 || ((index - 5) % 7 == 0))); }
and finally applied a where clause in a linq clause:
var needed = abses.Where(x => ValidIndex(x)).ToList(); //just for testing purposes dataGridView1.DataSource = needed;
:)
I bug
-
What is "this"?
IQueryable list = (from x in this
select x).Skip(5).Take(5);
I know the language. I've read a book. - _Madmatt
i thank you for your suggestion but it seems it would give me 5 sequential elements starting at item 6. where my for loop started at element 5 the next one would have been element 12 ( not 6 ) (i+=7) not (i++) "this" is the class this snippet is located in and it happens to inherit from List
-
i thank you for your suggestion but it seems it would give me 5 sequential elements starting at item 6. where my for loop started at element 5 the next one would have been element 12 ( not 6 ) (i+=7) not (i++) "this" is the class this snippet is located in and it happens to inherit from List
-
I don't think there is a direct way, but here is a workaround: Create a ValidationFunction( or a predicate or...) and use it for a where clause or a TakeWhile or... something like this for your example: I created a dummy class named... well Abs (original wright?)
public class Abs: IComparable
{
public string Name { get; set; }public int CompareTo(Abs other) { return this.Name.CompareTo(other.Name); } }
I populated a list of 100 Abs objects and sorted them:
for (int i = 0; i < 100; i++) { av = new Abs { Name = "Dap" + i.ToString() }; abses.Add(av); } abses.Sort();
created the ValidationFunction to match your for loop criteria:
private bool ValidIndex(Abs ab) { int index = abses.BinarySearch(ab); //can use abses.IndexOf(ab) if the class does bot implement Icomaparable //or if there is no custom IComparer provided return ((index > 0) && (index == 5 || ((index - 5) % 7 == 0))); }
and finally applied a where clause in a linq clause:
var needed = abses.Where(x => ValidIndex(x)).ToList(); //just for testing purposes dataGridView1.DataSource = needed;
:)
I bug
many thanks for the response. i was on a similar path at first but what i didn't like about it was that it forced me to go though the entire list. ( for each item find it's index and see if the math ( +7 in this case ) returns true ) where as the for (i=5, i< count i+=7) syntax will skip the 7 elements each iteration.
-
many thanks for the response. i was on a similar path at first but what i didn't like about it was that it forced me to go though the entire list. ( for each item find it's index and see if the math ( +7 in this case ) returns true ) where as the for (i=5, i< count i+=7) syntax will skip the 7 elements each iteration.
yeah you're right. You could use a Dictionary<key/index, value/this[i]> to fasten things up [added] Unless you're using this code in like a "critical" app, if the List/underlying class implements IComparable the speed is good enough. Just added two more fields to my super class Abs and modified the CompareTo to take that into account. Loaded 30,000 items in the list and the iteration happened in like some milliseconds or something. I haven't measured it but it happened instantly as far as the human eye is concerned. Bottom line test first and if slow improve. I once spent lots of time trying to improve a method knowing in my head that it could be faster. Then I realized that in the worst case possible the human eye could not perceive a delay to begin with. [/added]
I bug
-
perhaps i'm totally not getting it then. TakeWhile will still only return sequential items that will return true in the expression so skip(5).TakeWhile(....) will only return a list with one item ( number 5 ) for #6 will fail. assuming i have a list 1,2,3,4,5,6,7,8,9 and i write a for(int i=2; i<9, i+=3) this list will return 2,5,8 takewhile will return just 2
-
perhaps i'm totally not getting it then. TakeWhile will still only return sequential items that will return true in the expression so skip(5).TakeWhile(....) will only return a list with one item ( number 5 ) for #6 will fail. assuming i have a list 1,2,3,4,5,6,7,8,9 and i write a for(int i=2; i<9, i+=3) this list will return 2,5,8 takewhile will return just 2
TakeWhile and SkipWhile both take a predicate which you can code to return the appropriate elements.
I know the language. I've read a book. - _Madmatt
-
brain fart here :( how do you convert this to link
for (int i = 5; i < Count; i+=7) { MyList.Add(this[i]); }
Try this,
var result = this.Skip(5).TakeWhile((i, index) => (index % 7) == 0);
Vince Remember the dead, fight for the living
-
Try this,
var result = this.Skip(5).TakeWhile((i, index) => (index % 7) == 0);
Vince Remember the dead, fight for the living
many thanks for your answer, but it does not do the trick. your takewhile will stop on the first failure. and given a list 0...50 it will only return one item ( 6 ) first pass is (0%7)==0 (true) second pass is (1%7)==0 (false) where the expected result would be 6,13,20,27....... it'd be sweet if it could recuse and call skip and take 1 every 7 for now i ended up writing a custom GetEnumerator to return the desired indexes ( but i hate it)
-
many thanks for your answer, but it does not do the trick. your takewhile will stop on the first failure. and given a list 0...50 it will only return one item ( 6 ) first pass is (0%7)==0 (true) second pass is (1%7)==0 (false) where the expected result would be 6,13,20,27....... it'd be sweet if it could recuse and call skip and take 1 every 7 for now i ended up writing a custom GetEnumerator to return the desired indexes ( but i hate it)
try this:
var needed = this.Where((i, index) => ((index == 5 || ((index - 5) % 7 == 0)))).ToList();
Should work. Although the credit goes to Vince. TakeWhile or SkipWhile stops at the first false statement. Where doesn't. :)
I bug
modified on Monday, August 9, 2010 2:54 PM
-
try this:
var needed = this.Where((i, index) => ((index == 5 || ((index - 5) % 7 == 0)))).ToList();
Should work. Although the credit goes to Vince. TakeWhile or SkipWhile stops at the first false statement. Where doesn't. :)
I bug
modified on Monday, August 9, 2010 2:54 PM
You're right Moshu,
Vince Remember the dead, fight for the living
-
You're right Moshu,
Vince Remember the dead, fight for the living
-
try this:
var needed = this.Where((i, index) => ((index == 5 || ((index - 5) % 7 == 0)))).ToList();
Should work. Although the credit goes to Vince. TakeWhile or SkipWhile stops at the first false statement. Where doesn't. :)
I bug
modified on Monday, August 9, 2010 2:54 PM
i was down that path between posts here but the one thing that bugged me most about these solutions was that i had to traverse all elements in the list to find the ones i wanted ( every 7th in this case ) and though i agree with the comment you made a few posts ago about the actual cost here i still got a bit annoyed with it ;) anyhoo, i tried 2 options 1. generate a list of the desired index numbers and do my From clause from this list and my select clause would be something like select this[currentitem] but had a hard time generating a list like 5,12,19,26.... to do my FROM caluse on.
from idx in indexlist(5,12,19,26...)
select this[idx]2. create ForI extension which was not to my liking but was happier with that than that annoying other "cost" :) i decided to create a ForI extension
public static System.Collections.Generic.IEnumerable ForI(this IEnumerable source, int start, int skip) { int idx = start; while (idx < source.Count()) { yield return source.ElementAt(idx); idx += skip; } }
// so i could do something like
List nums = new List();
int q = 0;
while ((q++) <; 50)
nums.Add(q);foreach (var item in nums.ForI(5,7)) { Console.WriteLine(item); }
nonetheless i appreciate your comments, made me not give up looking thanks
-
Lol :-D
Vince Remember the dead, fight for the living
-
brain fart here :( how do you convert this to link
for (int i = 5; i < Count; i+=7) { MyList.Add(this[i]); }
Borrowed some from Mark N. I am ignorant on this API, but it seems that a pseudo code structure like this might also work. You could probably stuff it into a function that takes the initial Skip and the distance bewteen elements.
var collection = new collection();
var search = (from x in this select x);
search.Skip(5);
while (search.hasNext()){
collection.add(search.Take(1));
// might want to replace this with a loop of search.Skip(1) due to exceptions?
if (search.hasNext())
search.Skip(7-1);
} -
i was down that path between posts here but the one thing that bugged me most about these solutions was that i had to traverse all elements in the list to find the ones i wanted ( every 7th in this case ) and though i agree with the comment you made a few posts ago about the actual cost here i still got a bit annoyed with it ;) anyhoo, i tried 2 options 1. generate a list of the desired index numbers and do my From clause from this list and my select clause would be something like select this[currentitem] but had a hard time generating a list like 5,12,19,26.... to do my FROM caluse on.
from idx in indexlist(5,12,19,26...)
select this[idx]2. create ForI extension which was not to my liking but was happier with that than that annoying other "cost" :) i decided to create a ForI extension
public static System.Collections.Generic.IEnumerable ForI(this IEnumerable source, int start, int skip) { int idx = start; while (idx < source.Count()) { yield return source.ElementAt(idx); idx += skip; } }
// so i could do something like
List nums = new List();
int q = 0;
while ((q++) <; 50)
nums.Add(q);foreach (var item in nums.ForI(5,7)) { Console.WriteLine(item); }
nonetheless i appreciate your comments, made me not give up looking thanks
Nice solution cechode I would try to extract the Count() call of the loop because Count() can be costly over large collection. Count() will use the Count property if available(ICollection) but will iterate the source sequence otherwise. This will force you to traverse your sequence more time then the Where clause. Can be a problem if the source is allowed to change before the end of ForI.
cechode wrote:
public static System.Collections.Generic.IEnumerable ForI(this IEnumerable source, int start, int skip) { int idx = start; int count = source.Count() while (idx < count) { yield return source.ElementAt(idx); idx += skip; } }
Vince Remember the dead, fight for the living
-
brain fart here :( how do you convert this to link
for (int i = 5; i < Count; i+=7) { MyList.Add(this[i]); }
Hi cechode; The code snippet below will generate a sequence of integers that start at 5 and adds 12 to each previous value and will end with a value of 100 or less.
IEnumerable<int> index = Enumerable.Range(5, 100).Where(idx => (idx % 7) == 5 && idx <= 100);
Fernando
-
i was down that path between posts here but the one thing that bugged me most about these solutions was that i had to traverse all elements in the list to find the ones i wanted ( every 7th in this case ) and though i agree with the comment you made a few posts ago about the actual cost here i still got a bit annoyed with it ;) anyhoo, i tried 2 options 1. generate a list of the desired index numbers and do my From clause from this list and my select clause would be something like select this[currentitem] but had a hard time generating a list like 5,12,19,26.... to do my FROM caluse on.
from idx in indexlist(5,12,19,26...)
select this[idx]2. create ForI extension which was not to my liking but was happier with that than that annoying other "cost" :) i decided to create a ForI extension
public static System.Collections.Generic.IEnumerable ForI(this IEnumerable source, int start, int skip) { int idx = start; while (idx < source.Count()) { yield return source.ElementAt(idx); idx += skip; } }
// so i could do something like
List nums = new List();
int q = 0;
while ((q++) <; 50)
nums.Add(q);foreach (var item in nums.ForI(5,7)) { Console.WriteLine(item); }
nonetheless i appreciate your comments, made me not give up looking thanks