<commit_before>﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CollectionUtils.cs" company="Slash Games">
//   Copyright (c) Slash Games. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Slash.Collections.Utils
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    public static class CollectionUtils
    {
        #region Public Methods and Operators

        /// <summary>
        ///   Checks whether the first sequence contains all elements of the second one.
        /// </summary>
        /// <typeparam name="T">Type of the sequence to check.</typeparam>
        /// <param name="first">Containing sequence.</param>
        /// <param name="second">Contained sequence.</param>
        /// <returns>
        ///   <c>true</c>, if the first sequence contains all elements of the second one, and
        ///   <c>false</c> otherwise.
        /// </returns>
        public static bool ContainsAll<T>(this IEnumerable<T> first, IEnumerable<T> second)
        {
            return second.All(first.Contains);
        }

        /// <summary>
        ///   Compares two dictionary for equality.
        /// </summary>
        /// <typeparam name="TKey">Type of dictionary keys.</typeparam>
        /// <typeparam name="TValue">Type of dictionary values.</typeparam>
        /// <param name="first">First dictionary.</param>
        /// <param name="second">Second dictionary.</param>
        /// <returns>True if the two dictionaries are equal; otherwise, false.</returns>
        public static bool DictionaryEqual<TKey, TValue>(
            IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
        {
            if (first == second)
            {
                return true;
            }
            if ((first == null) || (second == null))
            {
                return false;
            }
            if (first.Count != second.Count)
            {
                return false;
            }

            EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default;

            foreach (KeyValuePair<TKey, TValue> kvp in first)
            {
                TValue secondValue;
                if (!second.TryGetValue(kvp.Key, out secondValue))
                {
                    return false;
                }

                if (kvp.Value is IEnumerable && secondValue is IEnumerable)
                {
                    IEnumerable enumerable1 = (IEnumerable)kvp.Value;
                    IEnumerable enumerable2 = (IEnumerable)secondValue;
                    if (!SequenceEqual(enumerable1.Cast<object>(), enumerable2.Cast<object>()))
                    {
                        return false;
                    }
                }
                else
                {
                    if (!comparer.Equals(kvp.Value, secondValue))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public static TValue GetValueOrDefault<TKey, TValue>(
            this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
        {
            TValue value;
            return dictionary.TryGetValue(key, out value) ? value : defaultValue;
        }

        public static TValue GetValueOrDefault<TKey, TValue>(
            this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> defaultValueProvider)
        {
            TValue value;
            return dictionary.TryGetValue(key, out value) ? value : defaultValueProvider();
        }

        /// <summary>
        ///   Compares the two passed lists for equality. Two lists are considered equal, if they contain equal elements in the same order.
        /// </summary>
        /// <param name="list1">First list to compare.</param>
        /// <param name="list2">Second list to compare.</param>
        /// <returns>
        ///   <c>true</c>, if either both or no list is <c>null</c>, both lists contain the same number of elements, and all elements are equal and in the same order.
        /// </returns>
        public static bool ListEqual(IList list1, IList list2)
        {
            if (list1 == list2)
            {
                return true;
            }

            if (list1 != null && list2 != null)
            {
                if (list1.Count != list2.Count)
                {
                    return false;
                }

                for (var i = 0; i < list1.Count; i++)
                {
                    if (!Equals(list1[i], list2[i]))
                    {
                        return false;
                    }
                }

                return true;
            }

            // One list is null.
            return false;
        }

        /// <summary>
        ///   Returns a random item from the specified sequence.
        /// </summary>
        /// <typeparam name="T">Type of sequence items.</typeparam>
        /// <param name="sequence">Sequence to get item from.</param>
        /// <returns>Time-dependent random item.</returns>
        public static T RandomItem<T>(this IEnumerable<T> sequence)
        {
            Random random = new Random();

            T current = default(T);
            int count = 0;
            foreach (T element in sequence)
            {
                count++;
                if (random.Next(count) == 0)
                {
                    current = element;
                }
            }
            if (count == 0)
            {
                throw new InvalidOperationException("Sequence was empty");
            }
            return current;
        }

        /// <summary>
        ///   Returns a random weighted item from the specified sequence.
        ///   Uses the specified function to get the weight of an item.
        ///   Idea was taken from http://stackoverflow.com/questions/17912005/quick-way-of-selecting-a-random-item-from-a-list-with-varying-probabilities-ba
        /// </summary>
        /// <typeparam name="T">Type of sequence items.</typeparam>
        /// <param name="sequence">Sequence to get item from.</param>
        /// <param name="getWeight">Function to get weight of an item.</param><commit_msg>ADDED: Slash.Collections - Added utility methods to return a default value if the specified sequence for RandomItem() is null or empty.<commit_after>﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CollectionUtils.cs" company="Slash Games">
//   Copyright (c) Slash Games. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Slash.Collections.Utils
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    public static class CollectionUtils
    {
        #region Public Methods and Operators

        /// <summary>
        ///   Checks whether the first sequence contains all elements of the second one.
        /// </summary>
        /// <typeparam name="T">Type of the sequence to check.</typeparam>
        /// <param name="first">Containing sequence.</param>
        /// <param name="second">Contained sequence.</param>
        /// <returns>
        ///   <c>true</c>, if the first sequence contains all elements of the second one, and
        ///   <c>false</c> otherwise.
        /// </returns>
        public static bool ContainsAll<T>(this IEnumerable<T> first, IEnumerable<T> second)
        {
            return second.All(first.Contains);
        }

        /// <summary>
        ///   Compares two dictionary for equality.
        /// </summary>
        /// <typeparam name="TKey">Type of dictionary keys.</typeparam>
        /// <typeparam name="TValue">Type of dictionary values.</typeparam>
        /// <param name="first">First dictionary.</param>
        /// <param name="second">Second dictionary.</param>
        /// <returns>True if the two dictionaries are equal; otherwise, false.</returns>
        public static bool DictionaryEqual<TKey, TValue>(
            IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
        {
            if (first == second)
            {
                return true;
            }
            if ((first == null) || (second == null))
            {
                return false;
            }
            if (first.Count != second.Count)
            {
                return false;
            }

            EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default;

            foreach (KeyValuePair<TKey, TValue> kvp in first)
            {
                TValue secondValue;
                if (!second.TryGetValue(kvp.Key, out secondValue))
                {
                    return false;
                }

                if (kvp.Value is IEnumerable && secondValue is IEnumerable)
                {
                    IEnumerable enumerable1 = (IEnumerable)kvp.Value;
                    IEnumerable enumerable2 = (IEnumerable)secondValue;
                    if (!SequenceEqual(enumerable1.Cast<object>(), enumerable2.Cast<object>()))
                    {
                        return false;
                    }
                }
                else
                {
                    if (!comparer.Equals(kvp.Value, secondValue))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public static TValue GetValueOrDefault<TKey, TValue>(
            this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
        {
            TValue value;
            return dictionary.TryGetValue(key, out value) ? value : defaultValue;
        }

        public static TValue GetValueOrDefault<TKey, TValue>(
            this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> defaultValueProvider)
        {
            TValue value;
            return dictionary.TryGetValue(key, out value) ? value : defaultValueProvider();
        }

        /// <summary>
        ///   Compares the two passed lists for equality. Two lists are considered equal, if they contain equal elements in the same order.
        /// </summary>
        /// <param name="list1">First list to compare.</param>
        /// <param name="list2">Second list to compare.</param>
        /// <returns>
        ///   <c>true</c>, if either both or no list is <c>null</c>, both lists contain the same number of elements, and all elements are equal and in the same order.
        /// </returns>
        public static bool ListEqual(IList list1, IList list2)
        {
            if (list1 == list2)
            {
                return true;
            }

            if (list1 != null && list2 != null)
            {
                if (list1.Count != list2.Count)
                {
                    return false;
                }

                for (var i = 0; i < list1.Count; i++)
                {
                    if (!Equals(list1[i], list2[i]))
                    {
                        return false;
                    }
                }

                return true;
            }

            // One list is null.
            return false;
        }

        /// <summary>
        ///   Returns a random item from the specified sequence.
        /// </summary>
        /// <typeparam name="T">Type of sequence items.</typeparam>
        /// <param name="sequence">Sequence to get item from.</param>
        /// <returns>Time-dependent random item.</returns>
        public static T RandomItem<T>(this IEnumerable<T> sequence)
        {
            Random random = new Random();

            T current = default(T);
            int count = 0;
            foreach (T element in sequence)
            {
                count++;
                if (random.Next(count) == 0)
                {
                    current = element;
                }
            }
            if (count == 0)
            {
                throw new InvalidOperationException("Sequence was empty");
            }
            return current;
        }

        /// <summary>
        ///   Returns a random item from the specified sequence or the specified default value if
        ///   the sequence is null or empty.
        /// </summary>
        /// <typeparam name="T">Type of sequence items.</typeparam>
        /// <param name="sequence">Sequence to get item from.</param>
        /// <param name="defaultValue">Default value to use if the sequence is null or empty.</param>
        /// <returns>Time-dependent random item.</returns>
        public static T RandomItemOrDefault<T>(this IEnumerable<T> sequence, T defaultValue)
        {
            IEnumerable<T> list = sequence as IList<T> ?? sequence.ToList();
            if (sequence == null || !list.Any())
            {
                return defaultValue;
            }

            return list.RandomItem();
        }

        /// <summary>
        ///   Returns a random item from the specified sequence or the default value of the
        ///   specified type if the sequence is null or empty.
        /// </summary>
        /// <typeparam name="T">Type of sequence items.</typeparam>
        /// <param name="sequence">Sequence to get item from.</param>
        /// <returns>Time-dependent random item.</returns>
        public static T RandomItemOrDefault<T>(this IEnumerable<T> sequence)
        {
            return sequence.RandomItemOrDefault(default(T));
        }

        /// <summary>
        ///   Returns a random weighted item from the specified sequence.
        ///   Uses the specified function to get the weight of an item.
        ///   Idea was taken from http://stackoverflow.com/questions/17912005/quick-way-of-selecting-a-random-item-from-a-list-with-varying-probabilities-ba
        /// </summary>
        /// <typeparam name="T">Type of sequence items.</typeparam>
        /// <param name="sequence">Sequence to get item from.</param>
        /// <param name="getWeight">Function to get weight of an item.</param>
{'fraction_non_alphanumeric': 0.13853382159883923, 'fraction_numerical': 0.00400746217093899, 'mean_word_length': 1.3580971000325839, 'pattern_counts': {'":': 0, '<': 177, '<?xml version=': 0, '>': 175, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4820191', 'n_tokens_mistral': 3544, 'n_tokens_neox': 3392, 'n_words': 1023}