2

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

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

我想遍历所有元素(使用 LINQ)并从我的列表中删除以其他元素开头的条目。

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

4

4 回答 4

10

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

sourceList.RemoveAll(x => sourceList.Any(y => x != y && x.StartsWith(y)));
于 2013-07-15T10:05:33.743 回答
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)));
于 2013-07-15T10:07:35.270 回答
1

怎么样

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

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

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

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

基于 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();

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

就我个人而言,我发现这种替代解决方案更难阅读,我的第一个答案更能表达要解决的问题。

于 2013-07-15T10:13:01.760 回答
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:\Dirand C:\Directory
  • 此代码使用不区分大小写的比较
  • 我这里没有使用纯 LINQ,但它是一种扩展方法
于 2013-07-15T10:14:03.933 回答