4

I need a helper method for adding axis labels to a chart. I don't want to add a label at every point along the axis that has values in the chart because that would get too busy. So I need to extract samples at regular intervals. So far I've come up with the following method which meets the requirements but I think there must be a neater way of accomplishing this with Linq. Can anyone think of how this could be made more concise (n represents the total number of samples I want back)?

public static List<T> Sample<T>(this List<T> list, int n)
{
  var samples = new List<T>();
  var divisor = list.Count/n;
  for (var i = 0; i < list.Count; i++)
    if (samples.Count == i/divisor)
      samples.Add(list[i]);
  return samples;
}
grenade
  • 31,451
  • 23
  • 97
  • 126
  • 3
    Are you sure sampling will give a nice Axis? I would look for Min and Max and build a scale using log10 arithmetic. Most Charting tools will do it like that. – H H Dec 14 '10 at 13:52
  • @Henk Holterman, Having looked at the output, I'm inclined to agree with you. – grenade Dec 14 '10 at 14:14
  • Sampling was the wrong way to solve this problem. I'll leave the question since maybe someone will need a sampler for something else one day but in the end, I did use the recommendation above. You can see the result here: http://stackoverflow.com/questions/25458/how-costly-is-reflection-really/4440657#4440657 – grenade Dec 14 '10 at 17:23

5 Answers5

5

Hm, what about:

return Enumerable.Range(0,n).Select(i=>list[(i*list.Count)/(n-1)]);

Not that it really matters, but this gives you a slightly better complexity (O(n) instead of O(list.Count)

MartinStettner
  • 28,719
  • 15
  • 79
  • 106
4

If I understand correctly:

int divisor = list.Count / n;
return list.Where((val, index) => index % divisor == 0).ToList();
Kobi
  • 135,331
  • 41
  • 252
  • 292
3
    public static List<T> Sample<T>(this List<T> list, int n)
    {
        Int32 count = list.Count;
        Int32 interval = count / n;

        return list.Where((item, index) => index % interval == 0).ToList();
    }
decyclone
  • 30,394
  • 6
  • 63
  • 80
0

This solution avoids using division in the iteration, which should perform faster.

public static List<T> Sample<T>(this List<T> list, int n)
{
    return list.Sample(list.Count / n).ToList();
}

public static IEnumerable<T> Sample<T>(this IEnumerable<T> enumerable, int interval) {
    var index = 0;
    foreach (var item in enumerable) {
        if (index == 0) {
            yield return item;
        }
        if (++index == interval) index = 0;
    }
}
tm1
  • 1,180
  • 12
  • 28
0

Try

list.Where((o, index) => index % divisor == 0)
MartinStettner
  • 28,719
  • 15
  • 79
  • 106
Aliostad
  • 80,612
  • 21
  • 160
  • 208