Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

IEnumerator во вложенных коллекциях

842
02 марта 2009 года
sigmov
301 / / 16.09.2008
Предо мной встала такая задача:
Имеем T[][]..........[] where T: IEnumerable и нужно это перевести в T[]
То есть многомерный массив в одномерный, причем упорядоченно.

С задачей справиля следующим образом:
Код:
public static IEnumerable GetIEnumerator<T>(this IEnumerable<T> obj)
            where T: IEnumerable
        {
            Queue<IEnumerable> Qu = new Queue<IEnumerable>();
            if (obj != null)
            {
                Qu.Enqueue(obj);
                while (Qu.Count > 0)
                {
                    foreach (object ie in Qu.Peek())
                    {
                        if (ie is IEnumerable) Qu.Enqueue(ie as IEnumerable);
                        else yield return ie;
                    }
                    Qu.Dequeue();
                }
            }
        }


Но вот такой примерчик:
 
Код:
var F = new object[][]{
                new object[]{1,2,3},
                new object[]{5,6, new int[]{7,8,9},10},
                new object[]{11,12,13}
            };

Вывелся как:
1, 2, 3, 5, 6, 10, 11, 12, 13, 7, 8, 9,

Т.е. сначала обработался уровень вложений 1, затем 2, затем 3.
Должно вывестись:
1, 2, 3, 5, 6, , 7, 8, 9, 10, 11, 12, 13

Буду благодарен за идеи!!!
842
02 марта 2009 года
sigmov
301 / / 16.09.2008
В принципе я сам разобрался

Код:
public static IEnumerable GetIEnumerator(this IEnumerable obj)
        {
            if (obj != null)
            {
                Stack<IEnumerator> stk = new Stack<IEnumerator>();
                stk.Push(obj.GetEnumerator());
                while (stk.Count > 0)
                {
                    while (stk.Peek().MoveNext())
                    {
                        if (stk.Peek().Current is IEnumerable)
                            stk.Push((stk.Peek().Current as IEnumerable).GetEnumerator());
                        else yield return stk.Peek().Current;
                    }
                    stk.Pop();
                }
            }
        }


Но если кто знает лучше способ - буду премного благодарен!!!
5
02 марта 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: sigmov
Но если кто знает лучше способ - буду премного благодарен!!!


Вот мой вариант.

Код:
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication14 {

    public static class FoldHelper {

        private enum ItemType {
            Object,
            Enuemrable
        }

        private static IEnumerable<T> DeepFold<T>(System.Collections.IEnumerable sequence, Dictionary<Type, ItemType> type_set) {
            foreach (object item in sequence) {
                Type item_type = item.GetType();
                ItemType item_type_tag;
                if (!type_set.TryGetValue(item_type, out item_type_tag)) {                    
                    item_type_tag = (item is System.Collections.IEnumerable) ?
                        ItemType.Enuemrable
                        : ItemType.Object;
                    type_set.Add(item_type, item_type_tag);
                }
                switch (item_type_tag) {
                    case ItemType.Enuemrable:
                        foreach (T sub_item in DeepFold<T>((System.Collections.IEnumerable)item, type_set))
                            yield return sub_item;
                        break;

                    case ItemType.Object:
                        yield return (T)item;
                        break;
                }
            }
        }

        public static IEnumerable<T> DeepFold<T>(System.Collections.IEnumerable sequence) {
            return DeepFold<T>(sequence, new Dictionary<Type, ItemType>());
        }


    }

    class Program {

        static void Main(string[] args) {
            foreach (int number in FoldHelper.DeepFold<int>(new object[] {
                new int[] { 1, 2, 3, 4},
                new int[] { 5, 6, 7 },
                new int[] { 8, 9 },
                new object[] { 10, 11, new int[] { 12, 13, 14 } },
                15,
                16,
                17
            })) {
                Console.WriteLine(number);
            }

            Console.ReadLine();
        }
    }
}
Словарь типов нужен для избежания многократной проверки на is IEnumerable.
Но всеравно это затратный метод.. нужно бы измерить его производительность профайлером.
5
02 марта 2009 года
hardcase
4.5K / / 09.08.2005
Сейчас проверил, всетаки кэш не нужен - операция IS в CLR очень шустро реализована.
 
Код:
public static IEnumerable<T> DeepFold<T>(System.Collections.IEnumerable sequence) {
            foreach (object item in sequence) {
                if (item is System.Collections.IEnumerable) {
                    foreach (T sub_item in DeepFold<T>((System.Collections.IEnumerable)item))
                        yield return sub_item;
                } else {
                    yield return (T)item;
                }
            }
        }
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог