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

5
我可以帮您进行翻译。以下是翻译的结果,请仔细阅读:

我想将大约有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


3
请提供您尝试过的代码。 - M.B.
2
除了问题,您应该包括到目前为止的代码尽力回答您的问题/疑问,因为[so]不是一个代码编写服务)。如果您有问题,请在进行更多研究后,发布您已经尝试过的内容,并提供一个清晰的解释说明哪里出了问题,同时提供一个**[mcve]**。我建议阅读如何提出好问题撰写完美问题。此外,请确保参观[tour]。 - Igor
1
我已经添加了我的代码。抱歉!我是新手。谢谢你的指点。 - Michael
2
这两个列表需要拥有相同数量的条目吗?如果是这样,那么在元素数量为奇数的情况下会发生什么?随机决定哪个列表获得额外的元素? - Matthew Watson
1
我会添加某种验证或代码,以确保我只获得偶数个条目。我只想先将列表拆分。一步一步来。 - Michael
5个回答

3
  1. 创建一个与字符串列表长度相同的bool数组。
  2. 将bool数组的一半填充为true,另一半填充为false
  3. 对bool数组进行随机排序。
  4. 遍历字符串列表。对于每个元素,如果bool数组中对应的元素是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个项目,因此对于您的问题来说,这并不重要。


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

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

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();

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


1
谢谢,这个解决方案有效。我还没有重新编写开头的部分。一旦我完成了其他要求,我会处理它。 - Michael

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

0

这里有一个简单的解决方案,符合您尝试解决问题的方式。

主要逻辑如下:

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);
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接