Метод Flatten Ruby в C#

Как мне сделать Ruby-метод Рубиновый метод «Flatten» в C#. Этот метод сглаживает зубчатый массив в одномерный массив.

Например:

s = [ 1, 2, 3 ]           #=> [1, 2, 3]
t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Здесь вы имеете дело с зубчатыми массивами (массивом массивов), а не с многомерными.

leppie 13.10.2008 13:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
1 221
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Рекурсивное решение:

IEnumerable Flatten(IEnumerable array)
{
    foreach(var item in array)
    {
        if (item is IEnumerable)
        {
            foreach(var subitem in Flatten((IEnumerable)item))
            {
                yield return subitem;
            }
        }
        else
        {
            yield return item;
        }
    }
}

РЕДАКТИРОВАТЬ 1:

Джон объясняет в комментариях, почему это не может быть общий метод, посмотрите!

Обновлено еще раз:

Мэтт предложил сделать это методом расширения. Вот и все, просто замените первую строку на:

public static IEnumerable Flatten(this IEnumerable array)

и вы можете использовать это так:

foreach(var item in myArray.Flatten()) { ... }

Моя первоначальная мысль была: "Почему это не универсальное?" - но, конечно, этого не может быть, потому что итеративная версия T очень редко бывает и T. (например, IEnumerable <object> по-прежнему является объектом, но IEnumerable <string> не является строкой.) Это может стоить того. разъясняя это в ответе.

Jon Skeet 13.10.2008 13:26

Также я не уверен, что есть какой-либо способ объявить строго типизированный рваный массив на C#? Это должен быть объект [], что означает, что IEnumerable является подходящим типом параметра для этого метода.

Matt Hamilton 13.10.2008 13:29

Мэтт: Не уверен, что вы имеете в виду под «строго типизированным рваным массивом», но int [] [] и int [,] (для зубчатых и прямоугольных массивов целых чисел соответственно) подойдут.

Jon Skeet 13.10.2008 13:31

@Matt: Действительно, я так и думал.

Alexander Kojevnikov 13.10.2008 13:32

@Jon: Я всегда стараюсь использовать самый простой подход, который сначала работает. По-видимому, это также самый общий: int [] [] и int [,] оба являются IEnumerables. Если вызывающая функция flatten () заранее знает типы, она всегда может привести к ним.

Alexander Kojevnikov 13.10.2008 13:48

@ Александр: Извините, я не понял. Я считаю, что вы получили правильный ответ, но, возможно, стоит немного пояснить, почему использование универсального метода (например, Flatten <T>) было бы контрпродуктивным. (Вы не можете преобразовать результат в IEnumerable <T> - вам придется использовать Enumerable.Cast <T>.)

Jon Skeet 13.10.2008 13:52

@Jon Я имею в виду рваный массив с отдельными значениями, а также вложенные массивы. Какой тип это {1, 2, {3, {4, 5}}, 6}? Некоторые из его элементов являются массивами, а другие - int.

Matt Hamilton 13.10.2008 13:53

@Alexander Это было бы еще лучше в качестве метода расширения!

Matt Hamilton 13.10.2008 13:57

Не придираться к мелочам, но разве имена методов не должны начинаться с заглавной буквы "Flatten" vs "Flatten"?

Luke Foust 13.10.2008 20:15

Я бы ответил в комментарии, но мне нужно больше 300 символов.

Решение @Alexander потрясающее, но оно сталкивается с проблемой с массивами строк. Поскольку строка реализует IEnumerable, я думаю, что она вернет каждый символ в каждой строке. Вы можете использовать общий параметр, чтобы сообщить ему, какие именно вещи вы надеетесь вернуть в этих случаях, например:

public static IEnumerable Flatten<T>(IEnumerable e)
{
    if (e == null) yield break;
    foreach (var item in e)
    {
        if (item is T)
           yield return (T)item;
        else if (item is IEnumerable)
        {
            foreach (var subitem in Flatten<T>((IEnumerable)item))
                yield return subitem;
        }
        else
           yield return item;
    }
}

Не могли бы вы просто использовать IEnumerable # SelectMany?

Другие вопросы по теме