LINQ用于删除从列表中的其他元素启动的元素

时间:2013-07-15 10:00:46

标签: c# linq

我有一个包含一些路径的列表List<string>

C:\Dir\Test\
C:\MyDir\
C:\YourDir\
C:\Dir\

我想浏览所有元素(使用LINQ)并删除从列表中的其他元素开始的条目。

在我的示例C:\Dir\Test\中以C:\Dir\开头 - 所以我想删除C:\Dir\Test\

4 个答案:

答案 0 :(得分:9)

使用List<T>.RemoveAll()方法:

sourceList.RemoveAll(x => sourceList.Any(y => x != y && x.StartsWith(y)));

答案 1 :(得分:3)

试试这个:

myInitialList.RemoveAll(x =>myInitialList.Any(q => q != x && q.StartsWith(x)));

或者,如果您想保留原始列表,这是获取与您的条件不符的所有记录的方法:

List<string> resultList = myInitialList.Except(x => myInitialList.Any(q => q != x && q.StartsWith(x)));

答案 2 :(得分:1)

怎么样

 mylist =  mylist.Where(a => mylist.All(b => b == a || !a.StartsWith(b)))
                 .Distinct()
                 .ToList();

这将返回一个新列表,其中列表中没有其他项目以它开头。

它有额外的检查,允许返回字符串相同的值,否则所有项目都将从列表中删除。

最后,不同的调用意味着删除了两次相同的字符串。

在nsinreal的评论和解决方案的基础上,您可以执行类似

的操作
myList = myList.OrderBy(d => d)
.Aggregate(new List<string>(),  
    (list, item) => {
        if (!list.Any(x => item.StartsWith(x)))
            list.Add(item);

        return list;
    }).ToList();

这通过减少每个测试的搜索列表的大小来降低解决方案的复杂性。它仍然需要初步排序。

我个人觉得这个替代解决方案难以阅读,我的第一个答案更能表达要解决的问题。

答案 3 :(得分:1)

最有效的方法是IMO对路径进行排序,然后迭代它们并仅返回那些不是以前一个开始的路径,即:

public static IEnumerable<string> 
GetRootPathsOfSet(this IEnumerable<string> paths)
{
    var sortedSet = new SortedSet<string>(paths,
                                          StringComparer.CurrentCultureIgnoreCase);
    string currRoot = null;
    foreach (var p in sortedSet)
    {
        if (currRoot == null ||
           !p.StartsWith(currRoot, StringComparison.InvariantCultureIgnoreCase))
        {
            currRoot = p;
            yield return currRoot;
        }
    }
}

一些注意事项:

  • 所有路径必须以尾部反斜杠终止,否则StartsWith方法不安全(例如C:\DirC:\Directory
  • 此代码使用不区分大小写的比较
  • 我这里没有使用纯LINQ,但它是一种扩展方法