Обратный IEnumerable.SelectMany? - PullRequest
1 голос
/ 19 июля 2011

Есть ли обратное / дополнение IEnumerable.SelectMany?То есть, есть ли метод вида IEnumerable<T>.InverseSelectMany(Func<IEnumerable<T>,T>), который найдет последовательность во входной последовательности и выполнит преобразование в один элемент, а затем снова выровняет все это?

Например, если выхотел заменить все escape-последовательности { 0x7E, 0x7E } в кадре HDLC только одним байтом 0x7E, вы могли бы сделать что-то вроде

byte[] byteArray = new byte[] { 0x01, 0x02, 0x7E, 0x7E, 0x04 }; // etc.
byte[] escapeSequence = new byte[] { 0x7E, 0x7E };
byte[] outputBytes = byteArray.InverseSelectMany<byte,byte>(x =>
{
   if (x.SequenceEqual(escapeSequence))
   {
      return new List<byte> { 0x7E };
   {
   else
   {
      return x;
   }
});

Имеет ли это какой-то смысл или я что-то упускаю здесь критическое?

1 Ответ

3 голосов
/ 19 июля 2011

Нет ничего такого встроенного. Первая проблема заключается в том, что, передав произвольному Func<IEnumerable<T>,T> перечислителю, он не будет знать, сколько байтов ему нужно «взять» и передать функции. Более разумный подход показан ниже, где вы можете передать последовательность, подлежащую замене, и другую последовательность, которую нужно заменить, и выполнить простой поиск.

public static class Extensions
{
    public static IEnumerable<T> ReplaceSequence<T>(this IEnumerable<T> original, IEnumerable<T> toSearch, IEnumerable<T> toReplace) where T : IEquatable<T>
    {
        T[] toSearchItems = toSearch.ToArray();
        List<T> window = new List<T>();
        foreach (T value in original)
        {
            window.Add(value);
            if (window.Count == toSearchItems.Length)
            {
                bool match = true;
                for (int i = 0; i < toSearchItems.Length; i++)
                {
                    if (!toSearchItems[i].Equals(window[i]))
                    {
                        match = false;
                        break;
                    }
                }

                if (match)
                {
                    foreach (T toReplaceValue in toReplace)
                    {
                        yield return toReplaceValue;
                    }

                    window.Clear();
                }
                else
                {
                    yield return window[0];
                    window.RemoveAt(0);
                }
            }
        }

        foreach (T value in window)
        {
            yield return value;
        }
    }
}
// http://stackoverflow.com/q/6751533/751090
public class StackOverflow_6751533
{
    public static void Test()
    {
        byte[] byteArray = new byte[] { 0x01, 0x02, 0x7E, 0x7E, 0x04 };
        byte[] escapeSequence = new byte[] { 0x7E, 0x7E };
        byte[] unescapedSequence = new byte[] { 0x7E };
        byte[] outputBytes = byteArray.ReplaceSequence(escapeSequence, unescapedSequence).ToArray();
        for (int i = 0; i < outputBytes.Length; i++)
        {
            Console.Write("{0:X2} ", (int)outputBytes[i]);
        }
        Console.WriteLine();
    }
}
...