Take 30 random elements from list - c#

I have a list of strings containing loads of hashtags with texts.
ex #csharp #java ect.
each hashtag is a own string in a List. I now want to randomly always console.writeline 30 items of that list.
List
List<string> Hashtags = new List<string>();
Writeline
foreach (var x in Hashtags) {
Console.WriteLine(x);
}
Ideally i never wanna have the same hashtag in the random 30.

You should try this:
var rnd = new Random();
foreach (var x in Hashtags.OrderBy(x => rnd.Next()).Take(30))
{
Console.WriteLine(x);
}
This has O(n^2) complexity, but is easily readable.
If you want efficiency try a Fisher-Yates Shuffle, it's O(n), but less readable:
var take = 30;
var rnd = new Random();
for (var i = 0; i < (Hashtags.Count < take ? Hashtags.Count : take); i++)
{
var j = rnd.Next(Hashtags.Count);
(Hashtags[i], Hashtags[j]) = (Hashtags[j], Hashtags[i]);
}
foreach (var x in Hashtags.Take(take))
{
Console.WriteLine(x);
}
Keep in mind, though, that it's best to instantiate Random once per thread, so this would be a better way:
[ThreadStatic]
private static Random rnd = new Random();

This should do. It is efficient, as it shuffles only the required amount of items, not the whole collection. You pass how many elements you want to fetch from the array as parameter(elementCount).
private static Random randomGenerator = new Random();
static void Main()
{
var hashtags = new List<string>() { "c#", "javascript", "ef", "asp.net" };
var result = GetRandomItems<string>(hashtags, 2);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
private static IEnumerable<T> GetRandomItems<T>(IEnumerable<T> collection, int elementCount)
{
var collectionCount = collection.Count();
if (elementCount > collectionCount)
{
elementCount = collectionCount;
}
var collectionCopy = collection.ToList();
var randomIndex = randomGenerator.Next(0, collectionCopy.Count);
for (var index = 0; index < elementCount; index++)
{
var tempElement = collectionCopy[index];
collectionCopy[index] = collectionCopy[randomIndex];
collectionCopy[randomIndex] = tempElement;
randomIndex = randomGenerator.Next(index + 1, collectionCopy.Count);
}
return collectionCopy.Take(elementCount);
}

Call 30 times Random.next
https://learn.microsoft.com/en-us/dotnet/api/system.random.next
var random = new Random();
//calls this n times in a loop:
Console.writeline(Hashtags[random.next(Hashtags.Count])

Got it working myself, little more verbose but hopefully easier to follow.
var random = new Random();
var uniques = Hashtags;
for (var i = 0; i < 30; i++) {
var index = random.Next(0, uniques.Count());
Console.WriteLine(uniques[index]);
uniques.RemoveAt(index);
}

Related

Cannot convert List<List<double>> to List<double>

I created a list which has 100 list each with 60 values, I need to run all of those 6000 values held within the list called population through a test (shown at the bottom error) and im not sure how i would go about converting the List<List<double>> to List<double>, or if i even can
You can either start off with a List<double> and use AddRange, so that you flatten the collections. Or you can convert it using SelectMany, like this:
var list = new List<double>();
foreach (...)
{
list.AddRange(someOtherList);
}
// Or
var list = new List<List<double>>();
var flattenedList = list.SelectMany(x => x);
I saw your code and think the following code can help you.
class Program
{
public static Random _random = new Random();
static void Main(string[] args)
{
List<List<double>> population = new List<List<double>>();
for (int k = 0; k < 100; k++)
{
var gWeights = new List<double>();
for (int i = 0; i < 60; i++)
{
var random = (_random.NextDouble() * 2) - 1;
gWeights.Add(random);
}
population.Add(gWeights);
}
List<double> population2 = new List<double>();
population.ForEach(x => population2.AddRange(x));
GetResult(population2);
Console.ReadKey();
}
public static void GetResult(List<double> items)
{
//your code
}
}

How can I add same numbers in existing list?

My function to generate random numbers is this:
public static List<int> GetRandomNumbers(int count)
{
HashSet<int> randomNumbers = new HashSet<int>();
Random random = new Random();
for (int i = 0; i < count; i++)
{
while(!randomNumbers.Add(random.Next(100, 999)));
}
return randomNumbers.ToList();
}
This is how I call it:
private void button1_Click(object sender, EventArgs e)
{
List<int> list = new List<int>();
list = GetRandomNumbers(5);
for (int i = 0; i < list.Count; i++)
{
MessageBox.Show(list[i].ToString());
}
}
Ok, so, what I want to do is, for example, if the list generated is the following:
152 582 254 891 421
I want to make the list be:
152 152 582 582 254 254 891 891 421 421
Basically, each number to be added one more time after itself in the list. How can I do this? (It would be good if you include a simple way to do this considering time not a problem, and maybe a better way to save time)
Thanks
Your question is unclear.
You can take a list (not a HashSet) with repeating elements and move every repetition to immediately follow the first occurrence like this:
var numbers = Enumerable.Range(1, count).Select(i => random.NextInt(0, 300));
return numbers.GroupBy(i => i).SelectMany(s => s).ToList();
You can take an existing list and make each element repeat twice like this:
list.SelectMany(o => Enumerable.Repeat(o, 2));
You could change your function slightly to:
private static Random random = new Random();
public static List<int> GetRandomNumbers(int count)
{
int value;
List<int> values = new List<int>();
HashSet<int> randomNumbers = new HashSet<int>();
for (int i = 0; i < count; i++)
{
while (!randomNumbers.Add(value = random.Next(100, 999)));
values.Add(value);
values.Add(value);
}
return values;
}
I think you just want something like this:
var list2 = new List<int>(list1.Count * 2);
foreach (var n in list1)
{
list2.Add(n);
list2.Add(n);
}
That will loop through the list and put each value into the second list twice.
I think you need to change your function as follows:
public static List<int> GetRandomNumbers(int count)
{
List<int> Result = new List<int>();
Random random = new Random();
for (int i = 0; i < count; i++)
{
int NewNumber = random.Next(100, 999);
Result.Add(NewNumber);
Result.Add(NewNumber);
}
return Result;
}
I tried the function above, it worked just like you said.

Select a number randomly from 1 to 99

I want to select a random number from 1 to 99. And then select the number again but this time discard the previous number. Can someone help me.
private List<int> numbers = Enumerable.Range(0, 100).ToList();
private Random rnd = new Random();
public int GetRandomInt()
{
var index = rnd.Next(0, numbers.Length);
var number = numbers[index];
numbers.RemoveAt(index);
return number;
}
Here's what I'd do:
var rnd = new Random();
var numbers = new Stack<int>(Enumerable.Range(1, 99).OrderBy(x => rnd.Next()));
You effectively are randomizing the list of numbers and then adding them to a stack. Now you just have to do this to get each number:
var next = numbers.Pop()
You stop when numbers.Count == 0. Simple.
Here is the revised version of Khanh TO, because it is not correct:
List<int> usedNumbers = new List<int>();
Random rand = new Random(new object().GetHashCode());
int number = 0;
for (int i = 0; i < 99; i++)
{
do
{
number = 1 + rand.Next(0, 99);
} while (usedNumbers.Contains(number));
usedNumbers.Add(number);
}
I usually do it with arrays.
Whenever you create a random number just put on the array. so next time check if the number is already generated by checking in the array.
Try this
IList<int> arr = Enumerable.Range(1, 99).ToList();
int randNum;
Random rnd = new Random();
randNum = rnd.Next(1, arr.Count());
MessageBox.Show(randNum.ToString());
arr = arr.Where(x => x != randNum).ToList();
Can I go for the shortest code, without a nested loop, or removing list elements.
Code 1
class Program
{
static Random rnd=new Random();
static void Main(string[] args)
{
var list=new SortedDictionary<double, int>();
// Fill list
for (int i=1; i<=99; i++)
{
list.Add(rnd.NextDouble(), i);
}
// List Automatically random
var random_int=list.Values.ToArray();
// random_int = {45, 7, 72, .. }
}
}
Code 2
class Program
{
static Random rnd=new Random();
static void Main(string[] args)
{
var list=new int[99];
// Fill list
for (int i=1; i<=99; i++)
{
list[i-1]=i;
}
Comparison<int> any=(x, y) =>
{
var z=2*rnd.NextDouble()-1;
return z.CompareTo(0);
};
// Randomize List
Array.Sort(list, any);
// list = { 49, 59, 21, 7, 18 ...}
}
}

How To Get Distinct Lists?

With the lists below, how can I get the distinct lists from the lists below without doing a full brute-force comparison? In the example, list2 and list3 are identical, so I would only want list1 and list2.
var list1 = new List<int>{1,2,3,4,5};
var list2 = new List<int>{2,3};
var list3 = new List<int>{3,2};
Replace the lists with a collection of HashSets.
You can then write
hashSets.Distinct(HashSet<int>.CreateSetComparer())
EDIT Use List<>.Sort + IEnumerable's .Any and .SequenceEqual
public static List<List<int>> Test1(List<int>[] lists)
{
var result = new List<List<int>>();
foreach(var list in lists)
{
list.Sort();
if(!result.Any(elm => elm.SequenceEqual(list)))
result.Add(list);
}
return result;
}
Here's a simple benchmark/test showing the HashSet method and the pre-.Sort .Any .SequenceEqual method. edit http://ideone.com/x3CJ8I of course ideone probably isn't the best benchmarking platform so feel free to run it on your own machine.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
public class Demo
{
public static void Main()
{
int tries = 100;
int count = 50;
int size = 1000;
Random rnd = new Random();
List<int>[] list;
Stopwatch sw;
sw = new Stopwatch();
for(int x=0; x<tries; x++)
{
list = new List<int>[count];
for(int y=0; y<count; y++)
{
list[y] = new List<int>();
for(int z=0; z<size; z++)
{
int n = rnd.Next();
list[y].Add(n);
}
if((y % 5) == 0 && y > 0)
{ // make repeated lists for the uniqueness check
list[y-1] = new List<int>(list[y]);
list[y-1].Reverse();
}
}
sw.Start();
Test1(list);
sw.Stop();
}
Console.WriteLine( sw.Elapsed.ToString() );
sw = new Stopwatch();
for(int x=0; x<tries; x++)
{
list = new List<int>[count];
for(int y=0; y<count; y++)
{
list[y] = new List<int>();
for(int z=0; z<size; z++)
{
int n = rnd.Next();
list[y].Add(n);
}
if((y % 5) == 0 && y > 0)
{ // make repeated lists for the uniqueness check
list[y-1] = new List<int>(list[y]);
list[y-1].Reverse();
}
}
sw.Start();
Test2(list);
sw.Stop();
}
Console.WriteLine( sw.Elapsed.ToString() );
}
public static List<List<int>> Test1(List<int>[] lists)
{
var result = new List<List<int>>();
foreach(var list in lists)
{
list.Sort();
if(!result.Any(elm => elm.SequenceEqual(list)))
result.Add(list);
}
return result;
}
public static List<HashSet<int>> Test2(List<int>[] lists)
{
var result = new List<HashSet<int>>();
foreach(var list in lists)
{
result.Add(new HashSet<int>(list));
}
result = result.Distinct(HashSet<int>.CreateSetComparer()).ToList();
return result;
}
}
EDIT I had time to modify the test, turns out the overhead of creating HashSets + .Distinct is edit EVERY SIMILAR to that of .Sort + .Any + .SequenceEqual. http://ideone.com/x3CJ8I
You could also concat the three lists and then do a .Distinct()
list<int> newList = list1.Concat(list2.Concat(list3)).Distinct();

Create 10 Unique numbers and save to array

I am trying to generate 10 unique random numbers and save it to an array.
Here is my code, but there is run-time error, but I dunno how.
Can someone help me please ?
static void Main(string[] args)
{
int [] generatedNum = new int[10];
bool duplicated;
int tempo;
Random random = new Random();
// Create first number
generatedNum[0] = random.Next(1, 25);
for (int i = 1; i < 10; i++)
{
tempo = random.Next(0, 25);
do
{
duplicated = false;
foreach (int x in generatedNum)
{
if (x == tempo)
duplicated = true;
}
if (duplicated == true)
tempo = random.Next(0, 25);
} while (duplicated == true);
// Save unique number to array
generatedNum[i] = tempo;
}
// To check the number saved
foreach (int i in generatedNum)
{
Console.WriteLine("{0}", generatedNum[i]);
}
}
This may helps:
public List<int> GetNumber()
{
Random random = new Random();
List<int> values = new List<int>();
values.Add(random.Next(0, 25));
while (values.Count < 10)
{
int newValue;
do
{
newValue = random.Next(0, 25);
} while (values.Contains(newValue));
values.Add(newValue);
}
return values;
}
To have x unique items out of an array of y, you need a shuffle bag.
You put your numbers 1-25 in a bag, shuffle it and then take the first 10 items. You will now have 10 random items between 1 & 25.
Your last foreach loop is invalid. i is the value, not index, so you can write it directly:
// To check the number saved
foreach (int i in generatedNum)
{
Console.WriteLine("{0}", i);
}
Change
foreach (int i in generatedNum)
{
Console.WriteLine("{0}", generatedNum[i]);
}
to
for (int j=0;j<generatedNum.Length;j++)
{
Console.WriteLine("{0}", generatedNum[j]);
}
Would this work
If you are allowed to use Linq you can try something like this
You can set the range you want
Random rnd = new Random();
var randomNumbers = Enumerable.Range(1, 100)
.Select(x => new { val = x, order = rnd.Next() })
.OrderBy(i => i.order)
.Select(x => x.val)
.Take(10).ToArray();
static void Main(string[] args)
{
var generatedNum = new List<int>();
var random = new Random();
while (generatedNum.Count < 10)
{
var tempo = random.Next(0, 25);
if (generatedNum.Contains(tempo)) continue;
generatedNum.Add(tempo);
}
foreach (var i in generatedNum)
{
Console.WriteLine("{0}", i);
}
}
And you problem was here no?
// To check the number saved
foreach (int i in generatedNum)
{
Console.WriteLine("{0}", generatedNum[i]);
}
/*try this,i used an arraylist to store the digits
using System;
using System.Collections;
public class SamplesArrayList
{
public static void Main()
{
// Creates and initializes a new ArrayList.
ArrayList values = new ArrayList();
Random random = new Random();
values.Add(random.Next(0, 25));
while (values.Count < 10)
{
int newValue;
do
{
newValue = random.Next(0, 25);
} while (values.Contains(newValue));
values.Add(newValue);
}
PrintValues(values);
}
public static void PrintValues(IEnumerable myList)
{
foreach (Object obj in myList)
Console.Write(" {0}", obj);
Console.WriteLine(myList);
}
}

Categories