使用LINQ对列表进行抽样

4

我需要一个帮助方法来给图表添加坐标轴标签。我不想在图表中每个具有值的点上都添加标签,因为那会变得太繁琐。所以我需要在固定间隔内提取样本。到目前为止,我已经想出了满足要求的以下方法,但我认为使用 Linq 可以更简洁地完成这项任务。有人能想到如何使它更加简洁明了吗?(n 表示我要返回的样本总数)

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;
}

3
你确定采样能得到一个好的坐标轴吗?我会查找最小值和最大值,并使用log10算法构建一个比例尺。大多数图表工具都会这样做。 - H H
@Henk Holterman,看了输出结果后,我倾向于同意您的观点。 - grenade
采样不是解决这个问题的正确方法。我会保留这个问题,因为也许有人将来需要采样器做其他事情,但最终,我确实使用了上面的建议。你可以在这里看到结果:https://dev59.com/WnVD5IYBdhLWcg3wTJvF#4440657 - grenade
5个回答

5

嗯,关于什么:

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

虽然这并不是非常重要,但这会使复杂度稍微更好一些 (O(n) 而不是 O(list.Count))


4
如果我理解正确:
int divisor = list.Count / n;
return list.Where((val, index) => index % divisor == 0).ToList();

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();
    }

0

这个解决方案在迭代过程中避免使用除法,应该会更快。

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;
    }
}

0

尝试

list.Where((o, index) => index % divisor == 0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接