Linq => Repeat mit jeweils neuer Intanze



  • Hallo Leute,

    ich möchte gern sowas machen:

    IEnumerable<Slot> list = Enumerable.Repeat(it=> new Slot(),10);
    

    gibts sowas? 🤡



  • Hallo,

    unter Is there an elegant way to repeat an action? finden sich einige Hinweise, warum es so etwas direkt in LINQ nicht gibt, aber auch ein paar Alternativen, z.B.:

    Enumerable.Range(0, 10).ToList().ForEach(arg => new Slot());
    

    Aber ich würde auch eher zu einer eigenen (Extension-)Methode tendieren.



  • Ja, Leute, bitte schreibt selbst ne Schleife oder ne eigene Hilfsmethode.
    Wenn ich sowas wie Range(0, 10).ToList().ForEach sehe ... nenene.



  • _slots = Enumerable.Range(0, slotCount)
    				.Select(it => new Slot(eventLogger, it))
    				.ToArray();
    

    :p 🕶 🤡 ⚠



  • Bonuspunkte gibt's erst wenn du es dabei noch schaffst Temp-Files zu generieren und insgesamt auf O(N^3) oder wenigstens O(N^2) zu kommen.



  • Ist Linq nicht so clever, und macht aus den 3 schleifen eine drauß?;)



  • Ist doch wurst ob eine oder drei Schleifen, interessant ist wie die Performance insgesamt ist.



  • NullBockException schrieb:

    _slots = Enumerable.Range(0, slotCount)
    				.Select(it => new Slot(eventLogger, it))
    				.ToArray();
    

    Ich sehe da nur eine Schleife in ToArray .

    Die Frage ist nur, ob beim Bauen des Arrays von vornherein die endgültige Größe berücksichtigt wird. Es würde mich nicht wundern, wenn Compiler und VM diese Information wegwerfen und ein exponentielles Vergrößern generieren würden.



  • Ich mach das ganze "Einmal" in der ganzen Anwendung beim Initialisieren.. ist doch scheiss egal ob das dann 5ns oer 10ms geht;) 😃 😃



  • TyRoXx schrieb:

    Die Frage ist nur, ob beim Bauen des Arrays von vornherein die endgültige Größe berücksichtigt wird. Es würde mich nicht wundern, wenn Compiler und VM diese Information wegwerfen und ein exponentielles Vergrößern generieren würden.

    Die Information bleibt nicht erhalten, weil Range() mit einem Iterator implementiert ist und weil keine Select() -Überladung für Collections existiert. Es ist aber ein Library- und kein Compiler- oder VM-Problem. Außerdem kann man beides nachrüsten:

    Select() für IReadOnlyList<> :

    public static class ReadOnlyCollectionExtensions
        {
            #region Details
            private interface ICollectionIterator<TSource>
            {
                IReadOnlyCollection<TResult> Select<TResult>(Func<TSource, TResult> selector);
            }
    
            private static Func<TSource, TResult> CombineSelectors<TSource, TMiddle, TResult>(
                Func<TSource, TMiddle> selector1, Func<TMiddle, TResult> selector2)
            {
                return x => selector2(selector1(x));
            }
    
            private static void CopyCollectionTo<T>(this IReadOnlyCollection<T> collection, T[] array, int arrayIndex)
            {
                if (array == null) throw new ArgumentNullException("array");
                if (array.Length < arrayIndex + collection.Count) throw new ArgumentOutOfRangeException("arrayIndex");
                if (collection.Count == 0) return;
    
                using (var enumerator = collection.GetEnumerator())
                {
                    enumerator.MoveNext(); // always returns true because collection.Count > 0
                    for (int i = 0; i < collection.Count; ++i)
                    {
                        array[arrayIndex + i] = enumerator.Current;
                        enumerator.MoveNext();
                    }
                }    
            }
    
            private class CollectionSelectIterator<TSource, TResult> : ICollection<TResult>, IReadOnlyCollection<TResult>, IEnumerator<TResult>,
                ICollectionIterator<TResult>
            {
                private readonly IReadOnlyCollection<TSource> source;
                private readonly Func<TSource, TResult> selector;
                private IEnumerator<TSource> enumerator;
                private int state;
    
                public CollectionSelectIterator(IReadOnlyCollection<TSource> source, Func<TSource, TResult> selector)
                {
                    this.source = source;
                    this.selector = selector;
                }
    
                // IEnumerator<>
                public TResult Current
                {
                    get
                    {
                        if (state != 2) throw new ArgumentOutOfRangeException();
                        return selector(enumerator.Current);
                    }
                }
                public void Dispose()
                {
                    if (enumerator != null) enumerator.Dispose();
                }
                object System.Collections.IEnumerator.Current { get { return Current; } }
                public bool MoveNext()
                {
                    if (state == 0)
                    {
                        Dispose();
                        enumerator = source.GetEnumerator();
                        state = 1;
                    }
                    if (state < 3)
                    {
                        if (enumerator.MoveNext())
                        {
                            state = 2;
                            return true;
                        }
                        state = 3;
                    }
                    return false;
                }
                public void Reset()
                {
                    if (enumerator != null) enumerator.Reset();
                    state = 1;
                }
    
                // IEnumerable<>
                public IEnumerator<TResult> GetEnumerator()
                {
                    return new CollectionSelectIterator<TSource, TResult>(source, selector);
                }
                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return GetEnumerator();
                }
    
                // IReadOnlyCollection<>
                public int Count { get { return source.Count; } }
    
                // ICollection<>
                public void Add(TResult item)
                {
                    throw new NotSupportedException();
                }
                public void Clear()
                {
                    throw new NotSupportedException();
                }
                public bool Contains(TResult item)
                {
                    return Enumerable.Contains(this, item);
                }
                public void CopyTo(TResult[] array, int arrayIndex)
                {
                    CopyCollectionTo(this, array, arrayIndex);
                }
                public bool IsReadOnly { get { return true; } }
                public bool Remove(TResult item)
                {
                    throw new NotSupportedException();
                }
    
                // ICollectionIterator<>
                public IReadOnlyCollection<TNewResult> Select<TNewResult>(Func<TResult, TNewResult> newSelector)
                {
                    return new CollectionSelectIterator<TSource, TNewResult>(source, CombineSelectors(selector, newSelector));
                }
            }
            #endregion // Details
    
            public static IReadOnlyCollection<TResult> Select<TSource, TResult>(
                this IReadOnlyCollection<TSource> collection, Func<TSource, TResult> selector)
            {
                if (collection == null) throw new ArgumentNullException("collection");
                if (selector == null) throw new ArgumentNullException("selector");
    
                var iterator = collection as ICollectionIterator<TSource>;
                if (iterator != null) return iterator.Select(selector);
                return new CollectionSelectIterator<TSource, TResult>(collection, selector);
            }
    
            public static T[] ToArray<T>(this IReadOnlyCollection<T> collection)
            {
                if (collection == null) throw new ArgumentNullException("collection");
                var result = new T[collection.Count];
                CopyCollectionTo(collection, result, 0);
                return result;
            }
            public static List<T> ToList<T>(this IReadOnlyCollection<T> collection)
            {
                if (collection == null) throw new ArgumentNullException("collection");
                return new List<T>(collection); // List<> constructor will cast collection to ICollection<> and preallocate the array
            }
        }
    

    Und eine Range() -Methode, die IReadOnlyList<> zurückgibt:

    public static class EnumerableHelper
        {
            #region Details
            private class RangeIterator : IList<int>, IReadOnlyList<int>, IEnumerator<int>
            {
                private readonly int start;
                private readonly int count;
                private int pos;
                private int state;
    
                public RangeIterator(int start, int count)
                {
                    this.start = start;
                    this.count = count;
                }
    
                // IEnumerator<>
                public int Current
                {
                    get
                    {
                        if (state != 1) throw new ArgumentOutOfRangeException();
                        return pos;
                    }
                }
                public void Dispose()
                {
                }
                object System.Collections.IEnumerator.Current { get { return Current; } }      
                public bool MoveNext()
                {
                    if (state == 1)
                    {
                        bool result = pos + 1 < start + count; // should not overflow because count != 0, hence pos < int.MaxValue
                        if (result) ++pos;
                        return result;
                    }
                    else
                    {
                        if (count == 0) return false;
                        pos = start;
                        state = 1;
                        return true;
                    }
                }
                public void Reset()
                {
                    state = 0;
                }
    
                // IEnumerable<>
                public IEnumerator<int> GetEnumerator()
                {
                    return new RangeIterator(start, count);
                }
                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return GetEnumerator();
                }
    
                // IReadOnlyCollection<>
                public int Count { get { return count; } }
    
                // IReadOnlyList<>
                public int this[int index]
                {
                    get
                    {
                        if (!Contains(index)) throw new ArgumentOutOfRangeException("index");
                        return start + index;
                    }
                    set { throw new NotSupportedException(); }
                }
    
                // ICollection<>
                public void Add(int item)
                {
                    throw new NotSupportedException();
                }
                public void Clear()
                {
                    throw new NotSupportedException();
                }
                public bool Contains(int item)
                {
                    return item >= start && item < start + count;
                }
                public void CopyTo(int[] array, int arrayIndex)
                {
                    if (array == null) throw new ArgumentNullException("array");
                    if (array.Length < arrayIndex + count) throw new ArgumentOutOfRangeException("arrayIndex");
    
                    for (int i = 0; i < count; ++i)
                        array[arrayIndex + i] = start + i;
                }
                public bool IsReadOnly { get { return true; } }
                public bool Remove(int item)
                {
                    throw new NotSupportedException();
                }
    
                // IList<>
                public int IndexOf(int item)
                {
                    if (!Contains(item)) return -1;
                    return item - start;
                }
                public void Insert(int index, int item)
                {
                    throw new NotSupportedException();
                }
                public void RemoveAt(int index)
                {
                    throw new NotSupportedException();
                }
            }
            #endregion // Details
    
            public static IReadOnlyList<int> Range(int start, int count)
            {
                long max = ((long) start) + count - 1;
                if (count < 0 || max > Int32.MaxValue) throw new ArgumentOutOfRangeException("count");
                return new RangeIterator(start, count);
            }
        }
    

    Ich habs nur so runtergetippt und nicht groß getestet, es sind also bestimmt Fehler drin. Aber wenn man das definiert hat, wird die Elementzahl von Select() -Statements konserviert, sofern vorhanden.

    Abgesehen davon nimmt man für den konkreten Anwendungsfall natürlich ein vorher alloziertes Array und eine Schleife.


Anmelden zum Antworten