如何从数组中选择值而不在C#中重复值

时间:2014-11-07 01:39:32

标签: c# arrays

  • 我正在使用C#,我有一个存储20 integers的数组。
  • 我有3个变量,我想将它们全部分配给array中随机选取的整数,但我必须这样做,以便从array中选取的值不一样。
  • 除了使用大量if statements
  • 之外,还有什么方法可以做到这一点

1 个答案:

答案 0 :(得分:3)

这个答案是基于ThariqNugrohotomo关于从混洗数组中选择三个不同值的建议。我实施了Fisher-Yates Shuffle algorithm版本,该版本基于DotNetPerls example。在执行混洗之后选择三个不同值的原因是由于源阵列可能具有重复值。如果我们简单地将它们洗牌,那么就有可能存在重复。

using System;
using System.Linq;

namespace ShuffleAndTakeUnique
{
    public class Program
    {
        static Random _random = new Random();

        static void Main(string[] args)
        {
            int[] array = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
            var values = Shuffle<int>(array).Distinct().Take(3).ToArray();

            foreach(var val in values)
            {
                Console.WriteLine(val);
            }
        }

        public static T[] Shuffle<T>(T[] source)
        {
            T[] array = new T[source.Length];
            Array.Copy(source, array, source.Length);
            var random = _random;

            for (int i = array.Length; i > 1; i--)
            {
                int j = random.Next(i);
                T tmp = array[j];
                array[j] = array[i - 1];
                array[i - 1] = tmp;
            }

            return array;
        }
    }
}

以下是较早的想法:

这是一个快速而肮脏的Console Application,可在int中存储三个唯一的List<int>值。然后,您可以将该列表中的值分配给变量。该列表用作确保值的唯一性的方法。这只是一个例子,所以显然可以根据您的需要改变它并清理它。

using System;
using System.Collections.Generic;

namespace App
{
    class Program
    {
        static Random random = new Random();
        static int[] array = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
        static List<int> results = new List<int>();

        static void Main(string[] args)
        {
            while (results.Count < 3)
            {
                int num = array[random.Next(array.Length)];
                if (!results.Contains(num))
                {
                    results.Add(num);
                }
            }

            foreach(var result in results)
            {
                Console.WriteLine(result);
            }
        }
    }
}

修改

这是一个使用泛型方法的示例,该方法将返回包含原始数组中唯一值的指定长度(最大为原始数组的最大值)的数组:

using System;
using System.Collections.Generic;
using System.Linq;

namespace GetUniqueValues
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] array1 = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
            var values1 = GetUniqueValues<int>(array1, 3);

            foreach (var val in values1)
            {
                Console.WriteLine(val);
            }

            string[] array2 = { "apple", "orange", "cherry", "melon", "grapefruit", "grapes", "peach", "watermelon" };
            var values2 = GetUniqueValues<string>(array2, 4);

            foreach (var val in values2)
            {
                Console.WriteLine(val);
            }
        }

        public static T[] GetUniqueValues<T>(T[] array, int valuesCount)
        {
            var values = new List<T>();

            if (array != null && array.Length > 0 && valuesCount > 0)
            {                   
                var distinctCount = array.Distinct().Count();
                if (valuesCount > distinctCount)
                {
                    valuesCount = distinctCount;
                }

                var random = new Random();

                while(values.Count < valuesCount)
                {
                    T val = array[random.Next(array.Length)];
                    if (!values.Contains(val))
                    {
                        values.Add(val);
                    }
                }
            }

            return values.ToArray();
        }
    }
}

请注意,我确保数组中不同值的数量不小于请求的值数。否则,我们将陷入无限循环。如果传递一个空数组或小于一的计数,它将返回一个空数组。我更喜欢null ...但是再一次,这取决于你。

另一种方法是将原始数组的副本作为List<T>传递,并在选中后删除任何值。这样,你再也无法选择它了。这是一个快速的,未经测试的草稿(我根本没有测试过这个),但你会明白这个想法:

while(values.Count < valuesCount && list.Count > 0)
{
    T val = list[random.Next(list.Count)];
    values.Add(val);
    list.RemoveAll(val);
}