コード例 #1
0
    /// <summary>
    /// Returns a data-producer that will ignore the
    /// elements from the start of a sequence while a condition
    /// (involving the elements's index in the sequence)
    /// is satsified; when the condition fails for an element,
    /// that element and all subsequent elements are yielded.
    /// </summary>
    /// <param name="source">The source data-producer</param>
    /// <param name="predicate">The condition to skip elements</param>
    public static IDataProducer <TSource> SkipWhile <TSource>(this IDataProducer <TSource> source, Func <TSource, int, bool> predicate)
    {
        source.ThrowIfNull("source");
        predicate.ThrowIfNull("predicate");

        DataProducer <TSource> ret = new();
        Action completion          = () => ret.End();

        bool skipping = true;
        int  index    = 0;

        source.DataProduced += value =>
        {
            skipping = skipping switch
            {
                true => predicate(value, index++),
                _ => skipping
            };

            switch (skipping)
            {
            // Note - not an else clause!
            case false:
                ret.Produce(value);
                break;
            }
        };
        source.EndOfData += completion;
        return(ret);
    }
コード例 #2
0
    /// <summary>
    /// Returns a data-producer that will yield a specified number of
    /// contiguous elements from the start of a sequence - i.e.
    /// "the first &lt;x&gt; elements".
    /// </summary>
    /// <param name="source">The source data-producer</param>
    /// <param name="count">The maximum number of elements to return</param>
    public static IDataProducer <TSource> Take <TSource>(this IDataProducer <TSource> source, int count)
    {
        source.ThrowIfNull("source");

        DataProducer <TSource> ret = new();

        Action           completion = () => ret.End();
        Action <TSource> production = null;

        production = value =>
        {
            switch (count)
            {
            case > 0:
                ret.Produce(value);
                count--;
                break;
            }

            switch (count)
            {
            case <= 0:
                source.EndOfData    -= completion;
                source.DataProduced -= production;
                ret.End();
                break;
            }
        };

        source.DataProduced += production;
        source.EndOfData    += completion;
        return(ret);
    }
コード例 #3
0
    /// <summary>
    /// Returns a data-producer that yeilds the values from the sequence, or which yields the given
    /// singleton value if no data is produced.
    /// </summary>
    /// <param name="defaultValue">The default value to be yielded if no data is produced.</param>
    /// <param name="source">The source data-producer.</param>
    public static IDataProducer <TSource> DefaultIfEmpty <TSource>(this IDataProducer <TSource> source, TSource defaultValue)
    {
        source.ThrowIfNull("source");

        DataProducer <TSource> ret = new();

        bool empty = true;

        source.DataProduced += value =>
        {
            empty = false;
            ret.Produce(value);
        };
        source.EndOfData += () =>
        {
            switch (empty)
            {
            case true:
                ret.Produce(defaultValue);
                break;
            }

            ret.End();
        };
        return(ret);
    }
コード例 #4
0
        /// <summary>
        /// Applies an accumulator function over the values yielded from
        /// a data-producer. The first value in the seqnence
        /// is used as the initial accumulator value, and the specified function is used
        /// to select the result value. If the sequence is empty then
        /// the default value for TSource is returned.
        /// </summary>
        /// <typeparam name="TSource">The type of data yielded by the data-source</typeparam>
        /// <param name="func">Accumulator function to be applied to each term in the sequence</param>
        /// <param name="source">The data-source for the values</param>
        public static IFuture <TSource> Aggregate <TSource>
            (this IDataProducer <TSource> source,
            DotNet20.Func <TSource, TSource, TSource> func)
        {
            source.ThrowIfNull("source");
            func.ThrowIfNull("func");

            Future <TSource> ret   = new Future <TSource>();
            bool             first = true;

            TSource current = default(TSource);

            source.DataProduced += value =>
            {
                if (first)
                {
                    first   = false;
                    current = value;
                }
                else
                {
                    current = func(current, value);
                }
            };
            source.EndOfData += () => ret.Value = current;

            return(ret);
        }
コード例 #5
0
        private static IOrderedDataProducer <TSource> OrderBy <TSource, TKey>(IDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector, IComparer <TKey> comparer, bool descending)
        {
            source.ThrowIfNull("source");
            comparer.ThrowIfNull("comparer");

            IComparer <TSource> itemComparer = new ProjectionComparer <TSource, TKey>(selector, comparer);

            if (descending)
            {
                itemComparer = itemComparer.Reverse();
            }

            // first, discard any existing "order by"s by going back to the producer
            IOrderedDataProducer <TSource> orderedProducer;
            bool first = true;

            while ((orderedProducer = source as IOrderedDataProducer <TSource>) != null)
            {
                if (first)
                {
                    // keep the top-most comparer to enforce a balanced sort
                    itemComparer = new LinkedComparer <TSource>(itemComparer, orderedProducer.Comparer);
                    first        = false;
                }
                source = orderedProducer.BaseProducer;
            }
            return(new OrderedDataProducer <TSource>(source, itemComparer));
        }
コード例 #6
0
    /// <summary>
    /// Applies an accumulator function over the values yielded from
    /// a data-producer. The first value in the seqnence
    /// is used as the initial accumulator value, and the specified function is used
    /// to select the result value. If the sequence is empty then
    /// the default value for TSource is returned.
    /// </summary>
    /// <typeparam name="TSource">The type of data yielded by the data-source</typeparam>
    /// <param name="func">Accumulator function to be applied to each term in the sequence</param>
    /// <param name="source">The data-source for the values</param>
    public static IFuture <TSource> Aggregate <TSource>
        (this IDataProducer <TSource> source,
        Func <TSource, TSource, TSource> func)
    {
        source.ThrowIfNull("source");
        func.ThrowIfNull("func");

        Future <TSource> ret   = new();
        bool             first = true;

        TSource current = default(TSource);

        source.DataProduced += value =>
        {
            switch (first)
            {
            case true:
                first   = false;
                current = value;
                break;

            default:
                current = func(current, value);
                break;
            }
        };
        source.EndOfData += () => ret.Value = current;

        return(ret);
    }
コード例 #7
0
    /// <summary>
    /// Returns a future to indicate whether the specified value
    /// is yielded by the data-source.
    /// </summary>
    /// <typeparam name="TSource">The type of data to be yielded</typeparam>
    /// <param name="source">The data-source</param>
    /// <param name="value">The value to detect from the data-source</param>
    /// <param name="comparer">The comparer to use to determine equality</param>
    public static IFuture <bool> Contains <TSource>(this IDataProducer <TSource> source, TSource value, IEqualityComparer <TSource> comparer)
    {
        source.ThrowIfNull("source");
        comparer.ThrowIfNull("comparer");

        return(source.Any(element => comparer.Equals(value, element)));
    }
コード例 #8
0
        /// <summary>
        /// Returns a future to a single value from a data-source that matches the
        /// specified condition; an exception
        /// is thrown if no matching values, or multiple matching values, are encountered.
        /// </summary>
        /// <param name="source">The source data-producer.</param>
        /// <param name="predicate">The condition to be satisfied.</param>
        /// <exception cref="InvalidOperationException">Zero or multiple matching terms are encountered.</exception>
        public static IFuture <TSource> Single <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            Future <TSource> ret = new Future <TSource>();

            TSource output   = default(TSource);
            bool    gotValue = false;

            source.DataProduced += value =>
            {
                if (predicate(value))
                {
                    if (gotValue)
                    {
                        throw new InvalidOperationException("More than one element in source data");
                    }
                    output   = value;
                    gotValue = true;
                }
            };

            source.EndOfData += () =>
            {
                if (!gotValue)
                {
                    throw new InvalidOperationException("No elements in source data");
                }
                ret.Value = output;
            };

            return(ret);
        }
コード例 #9
0
    /// <summary>
    /// Returns a future to the element at the given position in the sequence,
    /// or the default-value if the specified index is never reached
    /// </summary>
    /// <param name="source">The data-producer</param>
    /// <param name="index">The index of the desired trem in the sequence</param>
    /// <exception cref="ArgumentOutOfRangeException">If the specified index is negative</exception>
    public static IFuture <TSource> ElementAtOrDefault <TSource>(this IDataProducer <TSource> source, int index)
    {
        source.ThrowIfNull("source");
        switch (index)
        {
        case < 0:
            throw new ArgumentOutOfRangeException("index");
        }

        Future <TSource> ret = new();

        Action           completion = () => ret.Value = default(TSource);
        Action <TSource> production = null;

        production = value =>
        {
            switch (index)
            {
            case 0:
                ret.Value            = value;
                source.DataProduced -= production;
                source.EndOfData    -= completion;
                break;

            default:
                index--;
                break;
            }
        };

        source.DataProduced += production;
        source.EndOfData    += completion;

        return(ret);
    }
コード例 #10
0
        /// <summary>
        /// Returns a data-producer that will yield
        /// elements a sequence as long as a condition
        /// (involving the element's index in the sequence)
        /// is satsified; when the condition fails for an element,
        /// that element and all subsequent elements are ignored.
        /// </summary>
        /// <param name="source">The source data-producer</param>
        /// <param name="predicate">The condition to yield elements</param>
        public static IDataProducer <TSource> TakeWhile <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            DataProducer <TSource> ret  = new DataProducer <TSource>();
            Action           completion = () => ret.End();
            Action <TSource> production = null;

            int index = 0;

            production = value =>
            {
                if (!predicate(value, index++))
                {
                    ret.End();
                    source.DataProduced -= production;
                    source.EndOfData    -= completion;
                }
                else
                {
                    ret.Produce(value);
                }
            };

            source.DataProduced += production;
            source.EndOfData    += completion;
            return(ret);
        }
コード例 #11
0
        /// <summary>
        /// Returns a data-producer that will ignore the
        /// elements from the start of a sequence while a condition
        /// (involving the elements's index in the sequence)
        /// is satsified; when the condition fails for an element,
        /// that element and all subsequent elements are yielded.
        /// </summary>
        /// <param name="source">The source data-producer</param>
        /// <param name="predicate">The condition to skip elements</param>
        public static IDataProducer <TSource> SkipWhile <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            DataProducer <TSource> ret = new DataProducer <TSource>();
            Action completion          = () => ret.End();

            bool skipping = true;
            int  index    = 0;

            source.DataProduced += value =>
            {
                if (skipping)
                {
                    skipping = predicate(value, index++);
                }
                // Note - not an else clause!
                if (!skipping)
                {
                    ret.Produce(value);
                }
            };
            source.EndOfData += completion;
            return(ret);
        }
コード例 #12
0
        /// <summary>
        /// Returns a future to the element at the given position in the sequence,
        /// or the default-value if the specified index is never reached
        /// </summary>
        /// <param name="source">The data-producer</param>
        /// <param name="index">The index of the desired trem in the sequence</param>
        /// <exception cref="ArgumentOutOfRangeException">If the specified index is negative</exception>
        public static IFuture <TSource> ElementAtOrDefault <TSource>(this IDataProducer <TSource> source, int index)
        {
            source.ThrowIfNull("source");
            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            Future <TSource> ret = new Future <TSource>();

            Action           completion = () => ret.Value = default(TSource);
            Action <TSource> production = null;

            production = value =>
            {
                if (index == 0)
                {
                    ret.Value            = value;
                    source.DataProduced -= production;
                    source.EndOfData    -= completion;
                }
                else
                {
                    index--;
                }
            };

            source.DataProduced += production;
            source.EndOfData    += completion;

            return(ret);
        }
コード例 #13
0
        /// <summary>
        /// Returns a data-producer that will yield a specified number of
        /// contiguous elements from the start of a sequence - i.e.
        /// "the first &lt;x&gt; elements".
        /// </summary>
        /// <param name="source">The source data-producer</param>
        /// <param name="count">The maximum number of elements to return</param>
        public static IDataProducer <TSource> Take <TSource>(this IDataProducer <TSource> source, int count)
        {
            source.ThrowIfNull("source");

            DataProducer <TSource> ret = new DataProducer <TSource>();

            Action           completion = () => ret.End();
            Action <TSource> production = null;

            production = value =>
            {
                if (count > 0)
                {
                    ret.Produce(value);
                    count--;
                }
                if (count <= 0)
                {
                    source.EndOfData    -= completion;
                    source.DataProduced -= production;
                    ret.End();
                }
            };

            source.DataProduced += production;
            source.EndOfData    += completion;
            return(ret);
        }
コード例 #14
0
    /// <summary>
    /// Returns the last element in a sequence that satisfies a specified condition, as a future value.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">The sequence to an element from.</param>
    /// <param name="predicate">A function to test each element for a condition.</param>
    /// <returns>The last element in the specified sequence that passes the test in
    /// the specified predicate function, as a future value.
    /// The actual value can only be retrieved after the source has indicated the end
    /// of its data.
    /// </returns>
    public static IFuture <TSource> Last <TSource>(this IDataProducer <TSource> source, Func <TSource, bool> predicate)
    {
        source.ThrowIfNull("source");
        predicate.ThrowIfNull("predicate");

        Future <TSource> ret = new();

        bool    gotData = false;
        TSource prev    = default(TSource);

        source.DataProduced += value =>
        {
            if (predicate(value))
            {
                prev    = value;
                gotData = true;
            }
        };
        source.EndOfData += () =>
        {
            ret.Value = gotData switch
            {
                false => throw new InvalidOperationException("Sequence is empty"),
                      _ => prev
            };
        };

        return(ret);
    }
コード例 #15
0
    /// <summary>
    /// Returns a future to a single value from a data-source that matches the
    /// specified condition, or the default value if no matching values
    /// are encountered. An exception
    /// is thrown if multiple matching values are encountered.
    /// </summary>
    /// <param name="source">The source data-producer.</param>
    /// <param name="predicate">The condition to be satisfied.</param>
    /// <exception cref="InvalidOperationException">Multiple matching terms are encountered.</exception>
    public static IFuture <TSource> SingleOrDefault <TSource>(this IDataProducer <TSource> source, Func <TSource, bool> predicate)
    {
        source.ThrowIfNull("source");
        predicate.ThrowIfNull("predicate");

        Future <TSource> ret = new();

        TSource output   = default(TSource);
        bool    gotValue = false;

        source.DataProduced += value =>
        {
            if (predicate(value))
            {
                switch (gotValue)
                {
                case true:
                    throw new InvalidOperationException("More than one element in source data");

                default:
                    output   = value;
                    gotValue = true;
                    break;
                }
            }
        };

        source.EndOfData += () =>
        {
            ret.Value = output;
        };

        return(ret);
    }
コード例 #16
0
        /// <summary>
        /// Returns a future to the average of a sequence of values that are
        /// obtained by taking a transform of the input sequence
        /// </summary>
        /// <remarks>Null values are removed from the average</remarks>
        public static IFuture <TResult> Average <TSource, TResult>(this IDataProducer <TSource> source, Func <TSource, TResult> selector)
        {
            source.ThrowIfNull("source");
            selector.ThrowIfNull("selector");

            Future <TResult> ret = new Future <TResult>();
            TResult          sum = Operator <TResult> .Zero;
            int count            = 0;  // should this be long? Would demand a Operator.DivideInt64

            source.DataProduced += item => {
                if (Operator.AddIfNotNull(ref sum, selector(item)))
                {
                    count++;
                }
            };
            source.EndOfData += () => {
                if (count == 0)
                {
                    // check if Nullable<T> by seeing if default(T) is
                    // nullable; if so, return null; otherwise, throw
                    sum = default(TResult);
                    if (sum != null)
                    {
                        throw new InvalidOperationException("Cannot perform non-nullable average over an empty series");
                    }
                    ret.Value = sum;                     // null
                }
                else
                {
                    ret.Value = Operator.DivideInt32(sum, count);
                }
            };
            return(ret);
        }
コード例 #17
0
    /// <summary>
    /// Returns a future that indicates whether any suitable values are
    /// yielded by the data-producer. The future will return false
    /// for an empty sequence or one with no matching values, or true for a sequence with matching values.
    /// </summary>
    /// <param name="source">The data-producer to be monitored.</param>
    /// <param name="predicate">The condition that must be satisfied.</param>
    public static IFuture <bool> Any <TSource>(this IDataProducer <TSource> source, Func <TSource, bool> predicate)
    {
        source.ThrowIfNull("source");
        predicate.ThrowIfNull("predicate");

        Future <bool> ret = new();

        Action <TSource> production = null;
        Action           completion = () => ret.Value = false;

        production = value =>
        {
            if (predicate(value))
            {
                ret.Value            = true;
                source.DataProduced -= production;
                source.EndOfData    -= completion;
            }
        };

        source.DataProduced += production;
        source.EndOfData    += completion;

        return(ret);
    }
コード例 #18
0
        /// <summary>
        /// Returns a future to the minumum of a sequence of values that are
        /// obtained by taking a transform of the input sequence, using the default comparer
        /// </summary>
        /// <remarks>Null values are removed from the minimum</remarks>
        public static IFuture <TResult> Min <TSource, TResult>
            (this IDataProducer <TSource> source, DotNet20.Func <TSource, TResult> selector)
        {
            source.ThrowIfNull("source");
            selector.ThrowIfNull("selector");

            return(source.Select(selector).Min());
        }
コード例 #19
0
        /// <summary>
        /// Converts an IDataProducer into a list. An empty list is returned immediately,
        /// and any results produced are added to it.
        /// </summary>
        /// <remarks>This will force all values to be buffered</remarks>
        public static List <TSource> ToList <TSource>(this IDataProducer <TSource> source)
        {
            source.ThrowIfNull("source");

            List <TSource> list = new List <TSource>();

            source.DataProduced += value => list.Add(value);

            return(list);
        }
コード例 #20
0
    /// <summary>
    /// Returns the number of elements in a sequence, as a future value.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">A sequence that contains elements to be counted.</param>
    /// <returns>The number of elements in the input sequence, as a future value.
    /// The actual count can only be retrieved after the source has indicated the end
    /// of its data.
    /// </returns>
    public static IFuture <int> Count <TSource>(this IDataProducer <TSource> source)
    {
        source.ThrowIfNull("source");
        Future <int> ret   = new();
        int          count = 0;

        source.DataProduced += t => count++;
        source.EndOfData    += () => ret.Value = count;

        return(ret);
    }
コード例 #21
0
        /// <summary>
        /// Converts an IDataProducer into a future array.
        /// </summary>
        /// <remarks>This will force all values to be buffered</remarks>
        public static IFuture <TSource[]> ToFutureArray <TSource>(this IDataProducer <TSource> source)
        {
            source.ThrowIfNull("source");

            Future <TSource[]> ret  = new Future <TSource[]>();
            List <TSource>     list = source.ToList();

            source.EndOfData += () => ret.Value = list.ToArray();

            return(ret);
        }
コード例 #22
0
        /// <summary>
        /// Create a new OrderedDataProducer
        /// </summary>
        /// <param name="baseProducer">The base source which will supply data</param>
        /// <param name="comparer">The comparer to use when sorting the data (once complete)</param>
        public OrderedDataProducer(
            IDataProducer <T> baseProducer,
            IComparer <T> comparer)
        {
            baseProducer.ThrowIfNull("baseProducer");

            BaseProducer = baseProducer;
            Comparer     = comparer ?? Comparer <T> .Default;

            baseProducer.DataProduced += new Action <T>(OriginalDataProduced);
            baseProducer.EndOfData    += new Action(EndOfOriginalData);
        }
コード例 #23
0
    /// <summary>
    /// Create a new OrderedDataProducer
    /// </summary>
    /// <param name="baseProducer">The base source which will supply data</param>
    /// <param name="comparer">The comparer to use when sorting the data (once complete)</param>
    public OrderedDataProducer(
        IDataProducer <T> baseProducer,
        IComparer <T> comparer)
    {
        baseProducer.ThrowIfNull("baseProducer");

        this.baseProducer = baseProducer;
        this.comparer     = comparer ?? Comparer <T> .Default;

        baseProducer.DataProduced += OriginalDataProduced;
        baseProducer.EndOfData    += EndOfOriginalData;
    }
コード例 #24
0
        /// <summary>
        /// Returns a projection on the data-producer, using a transformation
        /// (involving the elements's index in the sequence) to
        /// map each element into a new form.
        /// </summary>
        /// <typeparam name="TSource">The source type</typeparam>
        /// <typeparam name="TResult">The projected type</typeparam>
        /// <param name="source">The source data-producer</param>
        /// <param name="projection">The transformation to apply to each element.</param>
        public static IDataProducer <TResult> Select <TSource, TResult>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, TResult> projection)
        {
            source.ThrowIfNull("source");
            projection.ThrowIfNull("projection");

            DataProducer <TResult> ret = new DataProducer <TResult>();
            int index = 0;

            source.DataProduced += value => ret.Produce(projection(value, index++));
            source.EndOfData    += () => ret.End();
            return(ret);
        }
コード例 #25
0
        /// <summary>
        /// Converts an IDataProducer into an IFuture[IEnumerable]. The results
        /// are buffered in memory (as a list), so be warned that this loses the "streaming"
        /// nature of most of the IDataProducer extension methods. The "future" nature of
        /// the result ensures that all results are produced before the enumeration can take
        /// place.
        /// </summary>
        /// <remarks>This will force all values to be buffered</remarks>
        public static IFuture <IEnumerable <TSource> > AsFutureEnumerable <TSource>(this IDataProducer <TSource> source)
        {
            source.ThrowIfNull("source");

            Future <IEnumerable <TSource> > ret = new Future <IEnumerable <TSource> >();

            List <TSource> list = new List <TSource>();

            source.DataProduced += value => list.Add(value);
            source.EndOfData    += () => ret.Value = list;

            return(ret);
        }
コード例 #26
0
        /// <summary>
        /// Converts an IDataProducer into a dictionary.
        /// </summary>
        /// <param name="elementSelector">A transform function to produce a result element value from each element.</param>
        /// <param name="keySelector">A function to extract a key from each element.</param>
        /// <param name="keyComparer">Used to compare keys.</param>
        /// <param name="source">The data source.</param>
        /// <remarks>This will force all values to be buffered</remarks>
        public static IDictionary <TKey, TElement> ToDictionary <TSource, TKey, TElement>(
            this IDataProducer <TSource> source,
            Func <TSource, TKey> keySelector, Func <TSource, TElement> elementSelector, IEqualityComparer <TKey> keyComparer)
        {
            source.ThrowIfNull("source");
            keySelector.ThrowIfNull("keySelector");
            elementSelector.ThrowIfNull("elementSelector");
            keyComparer.ThrowIfNull("keyComparer");

            Dictionary <TKey, TElement> dict = new Dictionary <TKey, TElement>(keyComparer);

            source.DataProduced += t => dict.Add(keySelector(t), elementSelector(t));
            return(dict);
        }
コード例 #27
0
        /// <summary>
        /// Returns a future to the sum of a sequence of values that are
        /// obtained by taking a transform of the input sequence
        /// </summary>
        /// <remarks>Null values are removed from the sum</remarks>
        public static IFuture <TResult> Sum <TSource, TResult>(this IDataProducer <TSource> source, Func <TSource, TResult> selector)
        {
            source.ThrowIfNull("source");
            selector.ThrowIfNull("selector");

            Future <TResult> ret = new Future <TResult>();
            TResult          sum = Operator <TResult> .Zero;

            source.DataProduced += item => {
                Operator.AddIfNotNull(ref sum, selector(item));
            };
            source.EndOfData += () => ret.Value = sum;
            return(ret);
        }
コード例 #28
0
        /// <summary>
        /// Converts an IDataProducer into a lookup.
        /// </summary>
        /// <param name="elementSelector">A transform function to produce a result element value from each element.</param>
        /// <param name="keySelector">A function to extract a key from each element.</param>
        /// <param name="keyComparer">Used to compare keys.</param>
        /// <param name="source">The data source.</param>
        /// <remarks>This will force all values to be buffered</remarks>
        public static ILookup <TKey, TElement> ToLookup <TSource, TKey, TElement>(
            this IDataProducer <TSource> source,
            Func <TSource, TKey> keySelector, Func <TSource, TElement> elementSelector, IEqualityComparer <TKey> keyComparer)
        {
            source.ThrowIfNull("source");
            keySelector.ThrowIfNull("keySelector");
            elementSelector.ThrowIfNull("elementSelector");
            keyComparer.ThrowIfNull("keyComparer");

            EditableLookup <TKey, TElement> lookup = new EditableLookup <TKey, TElement>(keyComparer);

            source.DataProduced += t => lookup.Add(keySelector(t), elementSelector(t));
            source.EndOfData    += () => lookup.TrimExcess();
            return(lookup);
        }
コード例 #29
0
        /// <summary>
        /// Applies an accumulator function over the values yielded from
        /// a data-producer, performing a transformation on the final
        /// accululated value. The specified seed value
        /// is used as the initial accumulator value, and the specified function is used
        /// to select the result value
        /// </summary>
        /// <typeparam name="TSource">The type of data yielded by the data-source</typeparam>
        /// <typeparam name="TResult">The final result type (after the accumulator has been transformed)</typeparam>
        /// <typeparam name="TAccumulate">The type to be used for the accumulator</typeparam>
        /// <param name="func">Accumulator function to be applied to each term in the sequence</param>
        /// <param name="resultSelector">Transformation to apply to the final
        /// accumulated value to produce the result</param>
        /// <param name="seed">The initial value for the accumulator</param>
        /// <param name="source">The data-source for the values</param>
        public static IFuture <TResult> Aggregate <TSource, TAccumulate, TResult>
            (this IDataProducer <TSource> source,
            TAccumulate seed, DotNet20.Func <TAccumulate, TSource, TAccumulate> func, DotNet20.Func <TAccumulate, TResult> resultSelector)
        {
            source.ThrowIfNull("source");
            func.ThrowIfNull("func");
            resultSelector.ThrowIfNull("resultSelector");

            Future <TResult> result = new Future <TResult>();

            TAccumulate current = seed;

            source.DataProduced += value => current = func(current, value);
            source.EndOfData    += () => result.Value = resultSelector(current);

            return(result);
        }
コード例 #30
0
    /// <summary>
    /// Returns the number of elements in the specified sequence satisfy a condition,
    /// as a future value.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">A sequence that contains elements to be tested and counted.</param>
    /// <param name="predicate">A function to test each element for a condition.</param>
    /// <returns>A number that represents how many elements in the sequence satisfy
    /// the condition in the predicate function, as a future value.
    /// The actual count can only be retrieved after the source has indicated the end
    /// of its data.
    /// </returns>
    public static IFuture <int> Count <TSource>(this IDataProducer <TSource> source, Func <TSource, bool> predicate)
    {
        source.ThrowIfNull("source");
        predicate.ThrowIfNull("predicate");
        Future <int> ret   = new();
        int          count = 0;

        source.DataProduced += t =>
        {
            if (predicate(t))
            {
                count++;
            }
        };
        source.EndOfData += () => ret.Value = count;

        return(ret);
    }