简体   繁体   中英

How to get random value from property from one List?

I have a List of 10,000 entries of type Element :

public class Element
{
    public Element()
    {
        this.Id = Guid.NewGuid();
    }

    public Guid Id { get; set };
}

And I have another List of 5,000 entries of type Link :

public class Link
{
    public Link(Guid ElementOne, Guid ElementTwo)
    {
        this.ElementOne = ElementOne;
        this.ElementTwo = ElementTwo;
    }

    public Guid ElementOne { get; set; }
    public Guid ElementTwo { get; set; }
}

I am populating my Lists here:

for (int i = 0; i < 10,000; i++)
    this.ListOfElements.Add(new Element());

for (int i = 0; i < 5,000; i++)
{
    this.ListOfLinks.Add(new Link(need ElementOne, need ElementTwo));
}

I am not sure what to pass for ElementOne and ElementTwo . I want to grab a random Id from the Element List ( Element.Id ) for both parameters and ensure they're unique ( ElementOne could never be ElementTwo ).

Sounds like you just need two random numbers. You can compare and repoll if you happen to get a duplicate.

for (int i = 0; i < 5,000; i++)
{
    int ele1 = Random.NextInt(10000);
    int ele2 = Random.NextInt(10000);

    while(ele1 == ele2){
        ele2 = Random.NextInt(10000);
    }
    this.ListOfLinks.Add(new Link(ListOfElements[ele1], ListOfElements[ele2]));
}

The code below will give a random array of the index to your list. So you can take randIndex[0] and randIndex[1] to get two random items.

            Random rand = new Random();
            List<string> myList = new List<string>() { "a","b","c"};
            int[] randIndex = myList.Select((x,i) => new {i = i, rand = rand.Next()}).OrderBy(x => x.rand).Select(x => x.i).ToArray();

You need to find next element which is not used, also using .OrderBy(i => Guid.NewGuid()) to get random element

private Element GetNextAvaibaleElement() {
  var usedElementIds = listOfLinks.Select(i => i.ElementOne).Union(listOfLinks.Select(i => i.ElementTwo));
  return listOfElements.Where(i => !usedElementIds.Contains(i.Id)).OrderBy(i => Guid.NewGuid()).FirstOrDefault();
}

and then get two available elements

for (int i = 0; i < 5,000; i++)
{
    this.ListOfLinks.Add(new Link(GetNextAvaibaleElement().Id,GetNextAvaibaleElement().Id));
}

See this dotnet fiddle here

Create an instance of the Random class somewhere.

Eg

static Random rdm = new Random();

Then, use this rdm instance to generate a random integer, delete that element from the list (so as not to reuse it), and keep going until you deplete your list.

List<Element> listOfElements; // list of 10k Elements

for (int i = 0; i < 5,000; i++)
{
    int r = rdm.Next(listOfElements.Count);
    Element elementOne = listOfElements[r]; 
    listOfElements.RemoveAt(r);
    r = rdm.Next(listOfElements.Count);
    Element elementTwo = listOfElements[r]; 
    this.ListOfLinks.Add(new Link(elementOne, elementTwo));
}

One approach to solving this is to create a list of integers representing the indexes into the ListOfElements , then order that list in a random way. Then you can simply reference items in the ListOfElements by index, sequentially walking through the randomized index list:

private static void Main()
{
    for (int i = 0; i < 10000; i++) ListOfElements.Add(new Element());

    // Create a randomly-ordered list of indexes to choose from
    var rnd = new Random();
    var randomIndexes = Enumerable.Range(0, ListOfElements.Count)
        .OrderBy(i => rnd.NextDouble()).ToList();

    // Now use our random indexes to pull unique items from the Element list
    for (int i = 0; i < 10000; i += 2)
        ListOfLinks.Add(new Link(ListOfElements[randomIndexes[i]].Id,
            ListOfElements[randomIndexes[i + 1]].Id));

    GetKeyFromUser("\nDone! Press any key to exit...");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM