逆 IEnumerable.SelectMany?

发布于 2024-11-24 17:38:16 字数 678 浏览 2 评论 0 原文

是否有 IEnumerable.SelectMany 的逆/补?也就是说,是否存在 IEnumerable.InverseSelectMany(Func,T>) 形式的方法,它将在输入序列中查找序列并执行转换为单个序列元素然后再次将整个事物展平?

例如,如果您想用单个字节 0x7E 替换 HDLC 帧中的所有转义序列 { 0x7E, 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;
   }
});

操作感觉还是我在这里错过了一些关键的东西?

Is there an inverse/complement of IEnumerable.SelectMany? That is, is there a method of the form IEnumerable<T>.InverseSelectMany(Func<IEnumerable<T>,T>) which will find a sequence in the input sequence and perform a transform to a single element and then flatten the whole thing out again?

For example, if you wanted to replace all escape sequences { 0x7E, 0x7E } in an HDLC frame with just a single byte 0x7E, you could do something like

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;
   }
});

Does that make any sense or am I missing something critical here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

楠木可依 2024-12-01 17:38:16

没有这样的内置东西。第一个问题是,通过将任意 Func,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();
    }
}

There isn't anything built-in like that. The first problem is that by passing an arbitrary Func<IEnumerable<T>,T> to the enumerator, it won't know how many bytes it will need to "take" and pass to the function. A more reasonable approach is shown below, where you can pass a sequence to be replaced, and the other sequence to replace, and do a simple search for that.

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();
    }
}
说好的呢 2024-12-01 17:38:16

我不知道这是否对其他人有帮助,但这在我看来是“相反的”。例如,如果您有一个带有 {1, 2, 3} 的对象 a.Items 和带有 { 的 b.Items 3, 4, 5} 调用 DeselectMany 将为您提供 6 个 KeyValuePairs 1:a, 2:a, 3:a, 3:b, 4:b, 5:b。您可以选择调用重载,让您返回除 KeyValuePair 之外的其他内容

    public static IEnumerable<KeyValuePair<TChild, TItem>> DeselectMany<TItem, TChild>(this IEnumerable<TItem> enumerable, Func<TItem, IEnumerable<TChild>> getElements)
    {
        return DeselectMany(
            enumerable,
            getElements,
            (c, i) => new KeyValuePair<TChild, TItem>(c, i)
            );
    }

    public static IEnumerable<TResult> DeselectMany<TItem, TChild, TResult>(this IEnumerable<TItem> enumerable, Func<TItem, IEnumerable<TChild>> getElements, Func<TChild, TItem, TResult> resultFactory)
    {
        foreach (var item in enumerable)
        {
            var elements = getElements(item);

            foreach (var element in elements)
            {
                var result = resultFactory(element, item);
                yield return result;
            }
        }
    }

I don't know if this would help anybody else, but this is "inverse" in my mind. If, for example, you had an object a.Items with {1, 2, 3} and b.Items with {3, 4, 5} calling DeselectMany will give you 6 KeyValuePairs of 1:a, 2:a, 3:a, 3:b, 4:b, 5:b. Optionally you can call the overload that lets you return something other than KeyValuePair

    public static IEnumerable<KeyValuePair<TChild, TItem>> DeselectMany<TItem, TChild>(this IEnumerable<TItem> enumerable, Func<TItem, IEnumerable<TChild>> getElements)
    {
        return DeselectMany(
            enumerable,
            getElements,
            (c, i) => new KeyValuePair<TChild, TItem>(c, i)
            );
    }

    public static IEnumerable<TResult> DeselectMany<TItem, TChild, TResult>(this IEnumerable<TItem> enumerable, Func<TItem, IEnumerable<TChild>> getElements, Func<TChild, TItem, TResult> resultFactory)
    {
        foreach (var item in enumerable)
        {
            var elements = getElements(item);

            foreach (var element in elements)
            {
                var result = resultFactory(element, item);
                yield return result;
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文