从一个列表创建两个随机列表

时间:2019-09-26 13:08:10

标签: c# asp.net-mvc

我想获取一个包含约12个对象的字符串列表,并将其拆分为两个字符串列表,但将其完全随机化。

列表示例:

清单1:

EXAMPLE 1
EXAMPLE 2
EXAMPLE 3
EXAMPLE 4
EXAMPLE 5
EXAMPLE 6
EXAMPLE 7
EXAMPLE 8

在这里应用一些逻辑...

结果给了我两个清单: 清单1:

EXAMPLE 5
EXAMPLE 6
EXAMPLE 1
EXAMPLE 8

清单2:

EXAMPLE 2
EXAMPLE 3
EXAMPLE 4
EXAMPLE 7

我是C#MVC的新手,所以我在Stack上找到了一些答案,但没有一个能够回答我的问题。

编辑: 到目前为止,我已经尝试过给我一个随机的团队成员。我现在想对此进行扩展,并如上所述创建两个列表。

  [HttpPost]
    public ActionResult Result(Models.TeamGenerator model)
    {
        var FormNames = model.Names;

        string[] lines = FormNames.Split(
            new[] { Environment.NewLine },
            StringSplitOptions.None);

        List<string> listOfLines = new List<string>();

        foreach (var i in lines)
        {
            listOfLines.Add(i);
        }
        string[] result1 = listOfLines.Where(item => item != string.Empty).ToArray();

        Random genRandoms = new Random();
        int aRandomTeam = genRandoms.Next(listOfLines.Count);

        string currName = listOfLines[aRandomTeam];

        return View();
    }

*编辑**感谢您的解决方案!现在,我的应用程序开始运行,并设法将其发布到网络https://www.teamgenerator.online

5 个答案:

答案 0 :(得分:3)

  1. 创建与字符串列表大小相同的布尔数组。
  2. true填充一堆布尔值,用false填充另一半。
  3. 随机排列一堆布尔值。
  4. 遍历字符串列表。对于每个元素,如果布尔数组中的对应元素为true,则将该元素包括在第一个列表中;否则,将其添加到列表中。否则将其包括在第二个列表中。

如果重要的话,这种方法可以使项目保持与原始数组相同的顺序。 (如果没有,则只需将整个字符串数组混洗,然后取前一半和后一半)。

示例代码:

using System;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        public static void Main()
        {
            var strings = Enumerable.Range(1, 20).Select(i => i.ToString()).ToList();

            var rng = new Random();
            int n = strings.Count;

            var include = // Create array of bools where half the elements are true and half are false
                Enumerable.Repeat(true, n/2) // First half is true
                .Concat(Enumerable.Repeat(false, n-n/2)) // Second half is false
                .OrderBy(_ => rng.Next()) // Shuffle
                .ToArray(); 

            var list1 = strings.Where((s, i) =>  include[i]).ToList(); // Take elements where `include[index]` is true
            var list2 = strings.Where((s, i) => !include[i]).ToList(); // Take elements where `include[index]` is false

            Console.WriteLine(string.Join(", ", list1));
            Console.WriteLine(string.Join(", ", list2));
        }
    }
}

这是一种完全不同的方法,它使用标准算法的修改版本从N个项目中选择K个项目(在这种情况下,K = N / 2):

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

namespace ConsoleApp1
{
    class Program
    {
        public static void Main()
        {
            var strings = Enumerable.Range(1, 20).Select(n => n.ToString()).ToList();

            var list1 = new List<string>();
            var list2 = new List<string>();

            var rng       = new Random();
            int available = strings.Count;
            int remaining = available / 2;

            foreach (var s in strings)
            {
                if (rng.NextDouble() < remaining / (double) available)
                {
                    list1.Add(s);
                    --remaining;
                }
                else
                {
                    list2.Add(s);
                }

                --available;
            }

            Console.WriteLine(string.Join(", ", list1));
            Console.WriteLine(string.Join(", ", list2));
        }
    }
}

这种方法比我的第一个解决方案性能更好,但是由于您的清单只有大约12个项目,因此这对您的问题而言并不重要。

答案 1 :(得分:2)

首先,尝试使用Random函数对列表进行混洗

static class MyExtensions
{
    private static Random rng = new Random();
    public static void Shuffle<T>(this IList<T> list)
    {
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            T value = list[k];
            list[k] = list[n];
            list[n] = value;
        }
    }
}

然后使用Linq

将列表分为两部分
    static void Main(String[] args)
    {
        List<string> examples = new List<string>();
        for(int i=1;i<=12;i++)
        {
            examples.Add($"Example {i}");
        }

        examples.Shuffle();

        var firstlist = examples.Take(examples.ToArray().Length / 2).ToArray();
        Console.WriteLine(String.Join(", ", firstlist));
        var secondlist = examples.Skip(examples.ToArray().Length / 2).ToArray();
        Console.WriteLine(String.Join(", ", secondlist));
        Console.ReadLine();
    }

输出看起来像这样

Example 6, Example 8, Example 3, Example 9, Example 5, Example 2
Example 10, Example 11, Example 4, Example 7, Example 12, Example 1

答案 2 :(得分:2)

您目前仅生成一个随机数并获得一个值。您需要做的是将其放入循环中,该循环的运行次数是列表中项目的一半。

var genRandoms = new Random();
var numberRequired = listOfLines.Count/2;
var output = new List<string>();
for (var i=0; i<numberRequired; i++)
{
    var aRandomTeam = genRandoms.Next(listOfLines.Count);
    output.Add(listOfLines[aRandomTeam]);
    listOfLines.RemoveAt(aRandomTeam);
}

此外,这是开头:

string[] lines = FormNames.Split(
        new[] { Environment.NewLine },
        StringSplitOptions.None);

    List<string> listOfLines = new List<string>();

    foreach (var i in lines)
    {
        listOfLines.Add(i);
    }
    string[] result1 = listOfLines.Where(item => item != string.Empty).ToArray();

可以重写为:

var listOfLines = FormNames.Split(
        new[] { Environment.NewLine },
        StringSplitOptions.RemoveEmptyEntries).ToList();

作为拆分的一部分删除空项目,并使用内置方法将其转换为列表。

答案 3 :(得分:1)

所以我在控制台应用程序中写了一个示例,但是这个概念的工作原理是一样的...请参见下面的代码块中的注释

样品清单

var fullList = new List<string>()
{
    "ITEM 01", "ITEM 02", "ITEM 03", "ITEM 04", "ITEM 05", "ITEM 06",
    "ITEM 07", "ITEM 08", "ITEM 09", "ITEM 10", "ITEM 11", "ITEM 12"
};

初始化两个列表以拆分值

var list1 = new List<string>();
var list2 = new List<string>();

创建两个随机列表

// Initialize one Random object to use throughout the loop
var random = new Random();

// Note: Start at count and count down because we will alter the count of the list
//       so counting up is going to mess up. Ex: Count = 4, Remove 1 (Count = 3), Loop won't go to 4
for(int i = fullList.Count; i > 0; i--)
{
    // Pull random index
    var randomIndex = random.Next(fullList.Count);

    // Pull item at random index
    var listItem = fullList[randomIndex];

    // If i is even, put it in list 1, else put it in list 2. 
    // You could do whatever you need to choose a list to put it
    if (i % 2 == 0)
        list1.Add(listItem);
    else
        list2.Add(listItem);

    // Remove random item from the full list so it doesn't get chosen again
    fullList.RemoveAt(randomIndex);
}

结果

Console.WriteLine("LIST 1");
Console.WriteLine(string.Join(Environment.NewLine, list1));

Console.WriteLine();
Console.WriteLine("LIST 2");
Console.WriteLine(string.Join(Environment.NewLine, list2));

-----------------------
LIST 1
ITEM 05
ITEM 04
ITEM 12
ITEM 11
ITEM 08
ITEM 01

LIST 2
ITEM 02
ITEM 03
ITEM 09
ITEM 06
ITEM 10
ITEM 07

答案 4 :(得分:0)

这是一个简单的solution,与您尝试解决此问题的方式一致。

主要逻辑如下:

while there are still items in the master list:
  choose a random number [0,list.count) as the current target index
  choose a random number [0,1] as the current target list to add to
  add the item chosen randomly to the randomly selected list
  remove the item chosen from the master list

代码如下:

        var random = new Random();

        var list = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"  };

        var newList1 = new List<string>();
        var newList2 = new List<string>();
        while(list.Count > 0)
        {
            //choose the index randomly
            int index = random.Next(list.Count);

            //get the item at the randomly chosen index
            string curItem = list[index];

            //choose the list randomly(1==newList1, 2==newList2)
            int listChoice = random.Next(2);

            //Add the item to the correct list
            if(listChoice == 1)
            {
                newList1.Add(curItem);
            }
            else
            {
                newList2.Add(curItem);
            }
            //finally, remove the element from the string
            list.RemoveAt(index);
        }