如何使用LINQ查询字符串的子集

时间:2014-04-16 15:43:14

标签: c# string linq

假设我有一个名为List<String>的无序letters

letters.Add("d.pdf");
letters.Add("a.pdf");
letters.Add("c.pdf");
letters.Add("b.pdf");
letters.Add("e.pdf");
letters.Add("f.pdf");

我想按字母顺序排列该列表,然后在bd(包括端点)之间获取元素,这样会返回一个新的列表,如{"b.pdf","c.pdf","d.pdf"}

3 个答案:

答案 0 :(得分:2)

简单foreach循环解决方案:

var letters = new List<string> {"d", "a", "c", "b", "e"};

            letters.Sort();

            var start = "b";
            var end = "d";
            var r = new List<string>();
            foreach (var l in letters)
            {
                if (l.CompareTo(start) >= 0 && l.CompareTo(end) <= 0)
                {
                    r.Add(l);
                }
            }

另一个简单的解决方案:

var letters = new List<string> {"d", "a", "c", "b", "e"};
letters.Sort();
 var startIndex = letters.IndexOf(letters.Find(l=> l.CompareTo(start) == 0));
 var endIndex = letters.IndexOf(letters.Find(l => l.CompareTo(end) == 0));
 var r = letters.GetRange(startIndex, endIndex - startIndex + 1);

如果你使用TakeWhile,这个解决方案应该可行,这更像是Linq。主要问题是在第一个集合索引中包含起始元素,否则TakeWhile将无法工作。

    var letters = new List<string> { "d", "a", "c", "b", "e" };
    letters.Sort();

    var start = "b";
    var end = "d";
    var startIndex = letters.IndexOf(letters.Find(l=> l.CompareTo(start) == 0));
    var r = letters.GetRange(startIndex, letters.Count - startIndex)
              .TakeWhile(l => l.CompareTo(start) >= 0 && l.CompareTo(end) <= 0).ToList();

答案 1 :(得分:0)

这适用于您的情况:

letters.OrderBy(x => x).TakeWhile(x => x != "e.pdf");

如果要概括它,可以编写扩展方法:

public static IEnumerable<TSource> GetRange<TSource>(
        this IEnumerable<TSource> source, 
        Func<TSource, bool> start,
        Func<TSource, bool> end)
{
     int counter = 0;
     foreach (var item in source)
     {
         if (start(item) || end(item))
         {
              yield return item;
              counter++;
              if(counter == 2) yield break;
         }else if (counter != 0) yield return item;
     }
} 

然后使用它:

letters.OrderBy(x => x).GetRange(x => x == "b.pdf", x => x == "d.pdf");

或者您可以在不使用LINQ的情况下执行此操作,List<T>也有GetRange方法:

letters.Sort();
int startIndex = letters.IndexOf("b.pdf");
int endIndex = letters.IndexOf("d.pdf");
var result = letters.GetRange(startIndex, endIndex - startIndex +1);

答案 2 :(得分:0)

我不确定是否有内置功能可以轻松支持,但添加新的扩展方法后,您可以轻松实现:

void Main()
{
    var letters = new List<string>();
    letters.Add("d.pdf");
    letters.Add("a.pdf");
    letters.Add("c.pdf");
    letters.Add("b.pdf");
    letters.Add("e.pdf");

    var results = letters
        .OrderBy(x => x)
        .SkipWhile(x => x != "b.pdf")
        .TakeTo(x => x == "d.pdf")
        .ToList();

}

static class Extensions
{
    public static IEnumerable<TValue> TakeTo<TValue>(this IEnumerable<TValue> source, Func<TValue, bool> predicate)
    {
        bool predicateReached = false;
        foreach (var value in source)
        {
            yield return value;         
            predicateReached = predicate(value);
            if (predicateReached) yield break;
        }
    }
}

TakeTo扩展方法的工作方式类似于TakeWhile扩展名,但它会产生所有值,直到并包含与给定谓词函数匹配的第一个值。