【问题标题】:How to filter a list?如何过滤列表?
【发布时间】:2009-11-16 17:42:15
【问题描述】:

这是一种应将已分配的用户从列表中取出的方法 并将未分配的保留在列表中。 GuidList 添加了 userId 单击按钮即可。 profileList 用于填充 gridView。

代码如下:

private VList<VW_profiles> FilterAssigned(VList<VW_profiles> profileList)
{
    VList<VW_profiles> sortedList = new VList<VW_profiles>();
    foreach(VW_profiles profile in profileList)
    {
        if(GuidList.Count > 0)
        {
            foreach(Guid userId in GuidList)
            {
                if(profile.UserId != userId)
                {
                    sortedList.Add(profile)
                }
            }
        }       
        else
        {
            sortedList = profileList;
        }
    }
    return sortedList;
}

现在这是我的问题。一切似乎都运作良好,直到 profileList 中的所有项目也已 添加到 GuidList。然后而不是对 两个 Guid ID,我们开始重新添加每个人。有没有人对如何做到这一点有任何建议,这是一种更有效的方法,并且一旦我们把所有东西都拿出来避免添加。

谢谢!

【问题讨论】:

  • 但是排序在哪里被准确地处理呢?
  • 为什么不用 lambda 表达式来做这件事,这样代码会少得多,而且速度会更快
  • 我会写一个 lambda,但我不明白你的代码应该做什么
  • 我想我应该说我使用的是 .net 2.0。

标签: c# sorting loops generic-list


【解决方案1】:

如果VList&lt;T&gt;List&lt;T&gt;,那么您可以这样做:

profileList.RemoveAll(profile => GuidList.Contains(profile.UserId));

如果性能是一个问题并且有很多 Guid 需要删除,那么您可以将 GuidList 设为 HashSet&lt;Guid&gt;

编辑基于cmets:如果你不想修改原始列表,那么这样做:

var filtered = new VList<VW_profiles>(
    profileList.Where(profile => !GuidList.Contains(profile.UserId)));

编辑如果您没有使用List&lt;T&gt;,这里有一种方法可以用于实现IList&lt;T&gt; 的可调整大小的列表,也可以用于数组(T[])。通过只从列表末尾删除项目,对于IList&lt;T&gt; 的大多数实现而言,O(n²) 算法将是 O(n)。

public static void RemoveAll<T>(this IList<T> list, Predicate<T> match)
{
    if (list == null)
        throw new ArgumentNullException("list");
    if (match == null)
        throw new ArgumentNullException("match");
    if (list is T[])
        throw new ArgumentException("Arrays cannot be resized.");

    // early out
    if (list.Count == 0)
        return;

    // List<T> provides special handling
    List<T> genericList = list as List<T>;
    if (genericList != null)
    {
        genericList.RemoveAll(match);
        return;
    }

    int targetIndex = 0;
    for (int i = 0; i < list.Count; i++)
    {
        if (!match(list[i]) && targetIndex != i)
        {
            list[targetIndex] = list[i];
            targetIndex++;
        }
    }

    // Unfortunately IList<T> doesn't have RemoveRange either
    for (int i = list.Count - 1; i >= targetIndex; i--)
    {
        list.RemoveAt(i);
    }
}

public static void RemoveAll<T>(ref T[] array, Predicate<T> match)
{
    if (array == null)
        throw new ArgumentNullException("array");
    if (match == null)
        throw new ArgumentNullException("match");

    int targetIndex = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if (!match(array[i]) && targetIndex != i)
        {
            array[targetIndex] = array[i];
            targetIndex++;
        }
    }

    if (targetIndex != array.Length)
    {
        Array.Resize(ref array, targetIndex);
    }
}

【讨论】:

  • +1,但请注意这将修改 original 列表。我不确定这是否是有意的。
【解决方案2】:

您的问题出在这段代码中:

foreach(Guid userId in GuidList)
{
    if(profile.UserId != userId)
    {
        sortedList.Add(profile)
    }
}

应该更像:

bool inList = false;
foreach(Guid userId in GuidList)
{
    if(profile.UserId == userId)
    {
        inList = true;
    }
}
if (!inList)
    sortedList.Add(profile)

或者,更多的 LINQ 风格:

bool inList = GuidList.Any(x => x == profile.UserId);
if (!inList)
    sortedList.Add(profile)

您当前的代码更像:

GuidList.Where(x => x != profile.UserId)
        .Foreach(x => sortedList.Add(x));

我认为这不是你想要的 :)

【讨论】:

  • 就是这样!我错过了那里的布尔开关。我喜欢使用 lambda 或 LINQ 的想法,但我正在使用 2.0 框架并且无法访问这些功能。
猜你喜欢
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 2020-06-12
  • 2018-09-06
  • 1970-01-01
  • 2021-12-23
  • 2016-01-09
  • 2013-08-15
相关资源
最近更新 更多