Используя C#, LINQ, как выбрать объекты между маркерами снова и снова?

Когда вы добавляете функцию url в браузер с помощью &name=azure, она устанавливает имя = azure в качестве заголовка http-запроса . Итак, если вы хотите отправить http-запрос с телом запроса, вы можете использовать почтальон для запуска функции Azure.

Вот мой тест: enter image description here enter image description here

5
задан David Smith 1 May 2009 в 22:45
поделиться

6 ответов

A pure-functional solution (mutation-free):

string[] strArray = { "aa", "bb", "xx", "cc", "xx", "dd", 
                      "ee", "ff", "xx", "xx", "gg", "xx" };

var result = 
 strArray.Aggregate((IEnumerable<IEnumerable<string>>)new IEnumerable<string>[0],
   (a, s) => s == "xx" ? a.Concat(new[] { new string[0] })
      : a.Any() ? a.Except(new[] { a.Last() })
                   .Concat(new[] { a.Last().Concat(new[] { s }) }) : a)
         .Where(l => l.Any());

// Test
foreach (var i in result)
  Console.WriteLine(String.Join(",", i.ToArray()));

If you want to filter out the results past the last marker:

string[] strArray = { "aa", "bb", "xx", "cc", "xx", "dd", 
                      "ee", "ff", "xx", "xx", "gg", "xx"};

var result = 
  strArray.Aggregate(
    new { C = (IEnumerable<string>)null, 
          L = (IEnumerable<IEnumerable<string>>)new IEnumerable<string>[0] },
    (a, s) => s == "xx" ? a.C == null
        ? new { C = new string[0].AsEnumerable(), a.L }
        : new { C = new string[0].AsEnumerable(), L = a.L.Concat(new[] { a.C }) } 
        : a.C == null ? a : new { C = a.C.Concat(new[] { s }), a.L }).L
          .Where(l => l.Any());

// Test
foreach (var i in result)
  Console.WriteLine(String.Join(",", i.ToArray()));
16
ответ дан 18 December 2019 в 06:51
поделиться

You can assign a group number to the items by using a group counter that you increase each time that you encounter an "xx" string. Then you filter out the "xx" strings, group on the group number, and filter out the empty groups:

int group = 0;
var lines =
   strArray
   .Select(s => new { Group = (s == "xx" ? ++group : group), Value = s })
   .Where(n => n.Value != "xx")
   .GroupBy(n => n.Group)
   .Where(g => g.Count() > 0);

foreach (var line in lines) {
   Console.WriteLine(string.Join(",", line.Select(s => s.Value).ToArray()));
}

Edit:
This solution will also remove the items before the first marker and after the last marker:

int group = 0;
var lines =
   strArray
   .Select(s => new { Group = s == "xx" ? group++ : group, Value = s })
   .GroupBy(n => n.Group)
   .Skip(1)
   .Where(g => g.Last().Value == "xx" && g.Count() > 1);

foreach (var line in lines) {
   Console.WriteLine(string.Join(",", line.Take(line.Count() - 1).Select(s => s.Value).ToArray()));
}
1
ответ дан 18 December 2019 в 06:51
поделиться

Лучшим подходом может быть написание универсального IEnumerable метода раздельного расширения, а затем выбрать и выбрать, какие части результатов вы хотите.

public static class IEnumerableExtensions
{
  public static IEnumerable<IEnumerable<TSource>> Split<TSource>(
                     this IEnumerable<TSource> source, TSource splitter)
  {
    if (source == null)
      throw new ArgumentNullException("source");
    if (splitter == null)
      throw new ArgumentNullException("splitter");

    return source.SplitImpl(splitter);
  }

  private static IEnumerable<IEnumerable<TSource>> SplitImpl<TSource>(
                     this IEnumerable<TSource> source, TSource splitter)
  {
    var list = new List<TSource>();

    foreach (TSource item in source)
    {
      if (!splitter.Equals(item))
      {
        list.Add(item);
      }
      else if (list.Count > 0)
      {
        yield return list.ToList();
        list.Clear();
      }
    }
  }
}
И использовать это так
static void Main(string[] args)
{
  string[] strArray = { "aa", "bb", "xx", "cc", "xx", "dd",
                        "ee", "ff", "xx", "xx", "gg", "xx" };

  var result = strArray.Split("xx");
  foreach (var group in result.Skip(1).Take(3))
  {
    Console.WriteLine(String.Join(",", group.ToArray()));
 }

  Console.ReadKey(true);
}
И вы получите желаемый результат
cc
dd,ee,ff
gg
5
ответ дан 18 December 2019 в 06:51
поделиться

Partioning lists/arrays isn't something LINQ is particularly well suited to. I recommend you write your own extension method(s) that returns an IEnumerable> using iterators (yield keyword) if you want to make it compatible with LINQ (i.e. fully lazy sequences). If you don't care about lazy evaluation, then the easiest thing would probably just to write a method that generates a list by iterating over the array and finally returns a jagged array (string[][]>).

0
ответ дан 18 December 2019 в 06:51
поделиться

Вы можете выбрать только те, которые не являются "xx", но если вам нужно разбивать строку каждый раз, когда вы ее найдете, вам придется использовать (для / для каждого) не query.

Запрос для извлечения «xx» будет

from s from array
where s != "xx"
select s
-1
ответ дан 18 December 2019 в 06:51
поделиться

Добавьте следующий метод расширения:

public static class SplitExtensions {
    public static IEnumerable<IEnumerable<T>> SplitBy<T>(this IEnumerable<T> src, T separator) {
        var group = new List<T>();
        foreach (var elem in src){
            if (Equals(elem, separator)){
                yield return group;
                group = new List<T>();
            } else{
                group.Add(elem);
            }
        }
        yield return group;
    }
}

Вот его использование:

string[] strArray = { "aa", "bb", "xx", "cc", "xx", "dd", "ee", "ff", "xx", "xx", "gg", "xx" };
var groups = from g in strArray.SplitBy("xx")
             where g.Any()
             select g;
2
ответ дан 18 December 2019 в 06:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: