How to access random item in list? - c#

I have an ArrayList, and I need to be able to click a button and then randomly pick out a string from that list and display it in a messagebox.
How would I go about doing this?

Create an instance of Random class somewhere. Note that it's pretty important not to create a new instance each time you need a random number. You should reuse the old instance to achieve uniformity in the generated numbers. You can have a static field somewhere (be careful about thread safety issues):
static Random rnd = new Random();
Ask the Random instance to give you a random number with the maximum of the number of items in the ArrayList:
int r = rnd.Next(list.Count);
Display the string:
MessageBox.Show((string)list[r]);

I usually use this little collection of extension methods:
public static class EnumerableExtension
{
public static T PickRandom<T>(this IEnumerable<T> source)
{
return source.PickRandom(1).Single();
}
public static IEnumerable<T> PickRandom<T>(this IEnumerable<T> source, int count)
{
return source.Shuffle().Take(count);
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
return source.OrderBy(x => Guid.NewGuid());
}
}
For a strongly typed list, this would allow you to write:
var strings = new List<string>();
var randomString = strings.PickRandom();
If all you have is an ArrayList, you can cast it:
var strings = myArrayList.Cast<string>();

You can do:
list.OrderBy(x => Guid.NewGuid()).FirstOrDefault()

Or simple extension class like this:
public static class CollectionExtension
{
private static Random rng = new Random();
public static T RandomElement<T>(this IList<T> list)
{
return list[rng.Next(list.Count)];
}
public static T RandomElement<T>(this T[] array)
{
return array[rng.Next(array.Length)];
}
}
Then just call:
myList.RandomElement();
Works for arrays as well.
I would avoid calling OrderBy() as it can be expensive for larger collections. Use indexed collections like List<T> or arrays for this purpose.

Create a Random instance:
Random rnd = new Random();
Fetch a random string:
string s = arraylist[rnd.Next(arraylist.Count)];
Remember though, that if you do this frequently you should re-use the Random object. Put it as a static field in the class so it's initialized only once and then access it.

I'll suggest different approach, If the order of the items inside the list is not important at extraction (and each item should be selected only once), then instead of a List you can use a ConcurrentBag which is a thread-safe, unordered collection of objects:
var bag = new ConcurrentBag<string>();
bag.Add("Foo");
bag.Add("Boo");
bag.Add("Zoo");
The EventHandler:
string result;
if (bag.TryTake(out result))
{
MessageBox.Show(result);
}
The TryTake will attempt to extract an "random" object from the unordered collection.

Why not:
public static T GetRandom<T>(this IEnumerable<T> list)
{
return list.ElementAt(new Random(DateTime.Now.Millisecond).Next(list.Count()));
}

ArrayList ar = new ArrayList();
ar.Add(1);
ar.Add(5);
ar.Add(25);
ar.Add(37);
ar.Add(6);
ar.Add(11);
ar.Add(35);
Random r = new Random();
int index = r.Next(0,ar.Count-1);
MessageBox.Show(ar[index].ToString());

I have been using this ExtensionMethod for a while:
public static IEnumerable<T> GetRandom<T>(this IEnumerable<T> list, int count)
{
if (count <= 0)
yield break;
var r = new Random();
int limit = (count * 10);
foreach (var item in list.OrderBy(x => r.Next(0, limit)).Take(count))
yield return item;
}

I needed to more item instead of just one. So, I wrote this:
public static TList GetSelectedRandom<TList>(this TList list, int count)
where TList : IList, new()
{
var r = new Random();
var rList = new TList();
while (count > 0 && list.Count > 0)
{
var n = r.Next(0, list.Count);
var e = list[n];
rList.Add(e);
list.RemoveAt(n);
count--;
}
return rList;
}
With this, you can get elements how many you want as randomly like this:
var _allItems = new List<TModel>()
{
// ...
// ...
// ...
}
var randomItemList = _allItems.GetSelectedRandom(10);

Printing randomly country name from JSON file.
Model:
public class Country
{
public string Name { get; set; }
public string Code { get; set; }
}
Implementaton:
string filePath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, #"..\..\..\")) + #"Data\Country.json";
string _countryJson = File.ReadAllText(filePath);
var _country = JsonConvert.DeserializeObject<List<Country>>(_countryJson);
int index = random.Next(_country.Count);
Console.WriteLine(_country[index].Name);

Why not[2]:
public static T GetRandom<T>(this List<T> list)
{
return list[(int)(DateTime.Now.Ticks%list.Count)];
}

Related

c# extension methods for generic array

I'm trying to make extension methods for generic array, so I could takeout random set of elements.
I made following extension methods for List<T> type and they work great, but I can't work out how to do exactly the same for generic array:
public static T Random<T>(this List<T> list)
{
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
public static IEquatable Random<IEquatable>(this List<IEquatable> list, List<IEquatable> hits)
{
int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
while (hits.Exists(h => h.Equals(list[rand])))
rand = GameManager.instance.functions.RandomInt(list.Count - 1);
return list[rand];
}
public static List<T> Random<T>(this List<T> list, int count)
{
List<T> result = new List<T>();
for (int i = 0; i < count; i++)
{
result.Add(list.Random());
}
return result;
}
public static List<IEquatable> RandomUnique<IEquatable>(this List<IEquatable> list, int count)
{
List<IEquatable> result = new List<IEquatable>();
for (int i = 0; i < count; i++)
{
result.Add(list.Random(result));
}
return result;
}
I tried to rework the first method like this:
public static IEnumerable Random<IEnumerable>(this IEnumerable list)
but it doesn't recognize list as an array so I can't get to it's length value.
I see a workaround, to do a List from Array, then get my random values and make array again, but it's seems like too much action for just taking eg. 2 random from 4 elements array.
Please advise
EDIT:
Thanks to Mathew in comments, I managed to construct the extension method for generic array correctly:
public static T Random<T>(this T[] list)
{
return list[GameManager.instance.functions.RandomInt(list.Length - 1)];
}
But ultimately I'll play around with the Dmitry's answer and try to make these for IEnumerable. Thank you very much!
EDIT2:
Thanks to Zastai, I changed all methods so they work for both List and generic array:
public static T Random<T>(this IReadOnlyList<T> list)
{
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
public static IEquatable Random<IEquatable>(this IReadOnlyList<IEquatable> list, List<IEquatable> hits)
{
int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
while (hits.Exists(h => h.Equals(list[rand])))
rand = GameManager.instance.functions.RandomInt(list.Count - 1);
return list[rand];
}
public static List<T> Random<T>(this IReadOnlyList<T> list, int count)
{
List<T> result = new();
for (int i = 0; i < count; i++)
{
result.Add(list.Random());
}
return result;
}
public static List<IEquatable> RandomUnique<IEquatable>(this IReadOnlyList<IEquatable> list, int count)
{
List<IEquatable> result = new();
for (int i = 0; i < count; i++)
{
result.Add(list.Random(result));
}
return result;
}
Doesn't work for strings (as in "abcdefg".Random()), but for my needs it's not neccessary.
IEnumerable is specifically just a sequence of values, and has no length.
IReadOnlyList on the other hand, is a list of values (so does have a length) and does not allow adding/removing values.
A .NET array implements both.
So if you change your extension methods to take IReadOnlyList<xxx> instead of List<xxx> they should automatically work on arrays too.
Instead of implementing extensions methods for List<T>, T[] etc. you can try implementing a
single routine for IEnumerable<T>, e.g.
public static partial class EnumerableExtensions {
public static T Random<T>(this IEnumerable<T> source) {
//DONE: do not forget to validate public methods' arguments
if (source is null)
throw new ArgumentNullException(nameof(source));
// If enumerable is a collection (array, list) we can address items explictitly
if (source is ICollection<T> collection) {
if (collection.Count <= 0)
throw new ArgumentOutOfRangeException(nameof(source),
$"Empty {nameof(source)} is not supported.");
return collection[GameManager.instance.functions.RandomInt(collection.Count - 1)];
}
// In general case we have to materialize the enumeration
var list = source.ToList();
if (list.Count <= 0)
throw new ArgumentOutOfRangeException(nameof(source),
$"Empty {nameof(source)} is not supported.");
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
}
Then you can use the same extension method with list, array etc.:
// Array
int demo1 = new int[] {4, 5, 6}.Random();
// List
double demo2 = new List<double>() {1.0. 3.0}.Random();
// String is not array or list but implements IEnumerable<char>
char demo3 = "abcdef".Random();
As an alternative to consider: You can use Reservoir sampling to select N items from a sequence of unknown length.
Here's a sample implementation:
/// <summary>Randomly selects n elements from a sequence of items.</summary>
public static List<T> RandomlySelectedItems<T>(IEnumerable<T> items, int n, System.Random rng)
{
// See http://en.wikipedia.org/wiki/Reservoir_sampling for details.
var result = new List<T>(n);
int index = 0;
foreach (var item in items)
{
if (index < n)
{
result.Add(item);
}
else
{
int r = rng.Next(0, index + 1);
if (r < n)
result[r] = item;
}
++index;
}
if (index < n)
throw new ArgumentException("Input sequence too short");
return result;
}

What is the name of this sorting algorithm in c#

public static int[] Sort(int[] ints)
{
var dictionary = new IndexedDictionary<int, int>();
foreach (var i in ints)
{
dictionary.Add(i, i);
}
for (int i = 0; i <= ints.Length - 1; i++)
{
var indexValue = dictionary[i].Key;
dictionary[indexValue - 1].Value = indexValue;
}
return dictionary.Values();
}
Is it a bucket sort? I've seen a few bucket sorts and they look more complicated than this. Also please ignore the IndexedDictionary class - its a custom class to allow for getting values by index.
Edit: CompuChip - if you want to see the IndexedDictionary:
public class IndexedDictionary<T, TY>
{
public class DicObject<T, Y>
{
public T Key { get; set; }
public Y Value { get; set; }
}
private HashSet<DicObject<T, TY>> list = new HashSet<DicObject<T, TY>>();
public void Add(T o, TY u)
{
list.Add(new DicObject<T, TY>{Key = o, Value = u});
}
public DicObject<T, TY> this[int i] {
get{return list.ElementAt(i);}
}
public T[] Keys()
{
return list.Select(x => x.Key).ToArray();
}
public TY[] Values()
{
return list.Select(x => x.Value).ToArray();
}
}
Its not the crux at all.
That is a form of pigeon hole sorting, but it's limited to only being capable of sorting collections with unique values ranging from 1 and up without gaps. (If you for example try to sort the array {4,3,2} it will crash.)
So, for any collection that it works for, it does the same thing as:
public static int[] Sort(int[] ints) {
return Enumerable.Range(1, ints.Length).ToArray();
}
The IndexedDictionary is only a complicated and slow way to iterate through the items in an arbitrary order and put each value in place according to the same arbitrary order so that they end up being sorted. You can do the same thing much simpler and faster with a regular array:
public static int[] Sort(int[] ints) {
int[] result = new int[ints.Length];
foreach (int value in ints) {
result[value - 1] = value;
}
return result;
}
For an implementation that works with collections that doesn't have to have a lowest value of 1 and be continuous, you would create an array that spans from the lowest to the highest value and put the values in it, then collect them in order:
public static int[] Sort(int[] ints) {
int min = ints.Min();
int max = ints.Max();
int?[] pigeonHoles = new int?[max - min + 1];
foreach (int value in ints) {
pigeonHoles[value - min] = value;
}
int[] result = new int[ints.Length];
int index = 0;
foreach (int? value in pigeonHoles) {
if (value.HasValue) {
result[index++] = value.Value;
}
}
return result;
}
I'm not sure how we can ignore the IndexedDictionary as it seems to be the crux of your algorithm, but assuming it works like a standard dictionary I would think this is basically an insert sort - you put all your values into a dictionary which inserts it in the right place to keep its keys sorted and in the end you just extract all the values which are in the proper order by then. However, all the hard work is invisible because it is inside the Dictionary class.
A similar solution in terms of standard classes would be something like
public static IEnumerable<int> Sort(int[] ints)
{
var dictionary = new Dictionary<int, bool>();
foreach (var i in ints)
{
dictionary.Add(i, false);
}
return dictionary.Keys;
}
(although this does not deal with numbers occurring more than once).

C# Enumerable.Take with default value

What is the best way to get exactly x values from an Enumerable in C#.
If i use Enumerable .Take() like this:
var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
The result will only have 10 elements.
I want to fill the missing entries with a default value.
Something like this:
var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int)); //Is there anything like this?
Is there such a function in C# and if not, what would be the best way to achieve this?
You could do something like:
var result = myList.Concat(Enumerable.Repeat(default(int), 20)).Take(20);
And it would be easy to turn this into an extension method:
public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int count, T defaultValue)
{
return list.Concat(Enumerable.Repeat(defaultValue, count)).Take(count);
}
But there is a subtle gotcha here. This would work perfectly fine for value types, for a reference type, if your defaultValue isn't null, you are adding the same object multiple times. Which probably isn't want you want. For example, if you had this:
var result = myList.TakeOrDefault(20, new Foo());
You are going to add the same instance of Foo to pad your collection. To solve that problem, you'd need something like this:
public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int count, Func<T> defaultFactory)
{
return list.Concat(Enumerable.Range(0, count).Select(i => defaultFactory())).Take(count);
}
Which you'd call like this:
var result = myList.TakeOrDefault(20, () => new Foo())
Of course, both methods can co-exist, so you could easily have:
// pad a list of ints with zeroes
var intResult = myIntList.TakeOrDefault(20, default(int));
// pad a list of objects with null
var objNullResult = myObjList.TakeOrDefault(20, (object)null);
// pad a list of Foo with new (separate) instances of Foo
var objPadNewResult = myFooList.TakeOrDefault(20, () => new Foo());
Its not there by default, but it's easy enough to write as an extension method
public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> items, int count, T defaultValue)
{
var i = 0;
foreach(var item in items)
{
i++;
yield return item;
if(i == count)
yield break;
}
while(i++<count)
{
yield return defaultValue;
}
}
Live example: http://rextester.com/XANF91263
What you're looking for is a general-purpose PadTo method, which extends the collection's length if needed using a given value.
public static IEnumerable<T> PadTo<T>(this IEnumerable<T> source, int len)
{
return source.PadTo(len, default(T));
}
public static IEnumerable<T> PadTo<T>(this IEnumerable<T> source, int len, T elem)
{
return source.PadTo(len, () => elem);
}
public static IEnumerable<T> PadTo<T>(this IEnumerable<T> source, int len, Func<T> elem)
{
int i = 0;
foreach(var t in source)
{
i++;
yield return t;
}
while(i++ < len)
yield return elem();
}
You can now express:
myList.Take(20).PadTo(20);
This is analogous to Scala's List[A].padTo
You could use Concat for this purpose. You can use a simple helper method to join this all together:
public IEnumerable<T> TakeSpawn(this IEnumerable<T> #this, int take, T defaultElement)
{
return #this.Concat(Enumerable.Repeat(defaultElement, take)).Take(take);
}
The idea is that you always append another enumerable on the end of the original enumerable, so if the input doesn't have enough elements, it will start enumerating from the Repeat.
There isn't anything in the .NET Framework, not that I'm aware of. This can be achieved easily using an extension method though and it works for all types if you supply a default value yourself:
public static class ListExtensions
{
public static IEnumerable<T> TakeOrDefault<T>(this List<T> list, int count, T defaultValue)
{
int missingItems = count - list.Count;
List<T> extra = new List<T>(missingItems);
for (int i = 0; i < missingItems; i++)
extra.Add(defaultValue);
return list.Take(count).Concat(extra);
}
}
I wrote a quick extension for this which depends on T being a value type.
public static class Extensions
{
public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int totalElements)
{
List<T> finalList = list.ToList();
if (list.Count() < totalElements)
{
for (int i = list.Count(); i < totalElements; i++)
{
finalList.Add(Activator.CreateInstance<T>());
}
}
return finalList;
}
}
Why not just write an extension method that checks the count and returns the default value for remaining entries:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
List<int> values = new List<int>{1, 2, 3, 4};
IEnumerable<int> moreValues = values.TakeOrDefault(3, 100);
Console.WriteLine(moreValues.Count());
moreValues = values.TakeOrDefault(4, 100);
Console.WriteLine(moreValues.Count());
moreValues = values.TakeOrDefault(10, 100);
Console.WriteLine(moreValues.Count());
}
}
public static class ExtensionMethods
{
public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> enumerable, int count, T defaultValue)
{
int returnedCount = 0;
foreach (T variable in enumerable)
{
returnedCount++;
yield return variable;
if (returnedCount == count)
{
yield break;
}
}
if (returnedCount < count)
{
for (int i = returnedCount; i < count; i++)
{
yield return defaultValue;
}
}
}
}
}

Class<type> in C#

I have a class and want to work with it as Lists: e.g. List<int>, List<string>, ... , List<T>
I have a class Randomizor which will take the collection data type that will be shuffled. How can I do so?
class Randomizor<T>
{
public Randomizor()
{
}
public Array Shuffle(Array toShuffle)
{
}
}
Create a generic class like so:
class Randomizer<TList, TType> where TList : IList<TType>
{
public TList Randomize(TList list)
{
// ...
}
}
Or like so:
class Randomizer<T>
{
public IList<T> Randomize(IList<T> list)
{
// ...
}
}
Not very clear question... do you mean something like this?
public static class Randomizer<T>
{
public static T GetRandom(List<T> list)
{
T value = default(T);
// Perform some random logic.
return value;
}
}
EDIT: I found two superior impementations after a little digging so I would suggest those in preference.
An extension method for this purpose and already been suggested previously here
I include the code paraphrased to Shuffle below.
public static IEnumerable<T> Shuffle<T> (this IEnumerable<T> source)
{
Random random = new Random ();
T [] copy = source.ToArray ();
for (int i = copy.Length - 1; i >= 0; i--)
{
int index = random.Next (i + 1);
yield return copy [index];
copy [index] = copy [i];
}
}
And an interesting solution adapted from this linq approach
public static IEnumerable<T> Shuffle<T> (this IEnumerable<T> source)
{
Random random = new Random ();
return source.OrderBy(i => Random.Next()).AsEnumerable();
}
The orignal answer but slower than the edits
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> sequence)
{
Random random = new Random();
List<T> copy = sequence.ToList();
while (copy.Count > 0)
{
int index = random.Next(copy.Count);
yield return copy[index];
copy.RemoveAt(index);
}
}
If you like one of these you should up vote the linked answer.
If you are very concerned about randomness, you could upgrade to one of the RNG algorithms from the Crypto API and seed it with some non deterministic value, like somthing generated from recent mouse activity. I suspect that would be overkill and it would degrade performance.
class Randomizor<T>
{
public Randomizor()
{
}
public List<T> Shuffle(List<T> toShuffle)
{
}
}
class Randomizer<T>
{
public Randomizer(ICollection<T> collection)
{
//Do something with collection using T as the type of the elements
}
}
However you may want to go for a generic extension method
static class Randomizer
{
public static void Randomize<T>(this ICollection<T> collection)
{
//randomize the collection
}
}
and the usage:
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
list.Randomize();
Maybe like this:
public List<T> Shuffle<T>(List<T> toShuffle)
{
return toShuffle.OrderBy(x => Guid.NewGuid()).ToList();
}
Or as an extension method
public static class Extensions
{
public static List<T> Shuffle<T>(this List<T> toShuffle)
{
return toShuffle.OrderBy(x => Guid.NewGuid()).ToList();
}
}

How to specify parameter for generic list type extension method in c#

I am trying to make an extension method that will shuffle the contents of a generic list collection regardless of its type however im not sure what to put in between the <..> as the parameter. do i put object? or Type? I would like to be able to use this on any List collection i have.
Thanks!
public static void Shuffle(this List<???????> source)
{
Random rnd = new Random();
for (int i = 0; i < source.Count; i++)
{
int index = rnd.Next(0, source.Count);
object o = source[0];
source.RemoveAt(0);
source.Insert(index, o);
}
}
You need to make it a generic method:
public static void Shuffle<T>(this List<T> source)
{
Random rnd = new Random();
for (int i = 0; i < source.Count; i++)
{
int index = rnd.Next(0, source.Count);
T o = source[0];
source.RemoveAt(0);
source.Insert(index, o);
}
}
That will allow it to work with any List<T>.
You just make your own method generic:
public static void Shuffle<T>(this List<T> source)
Slightly off-topic, but a Fisher-Yates shuffle will have less bias and better performance than your method:
public static void ShuffleInPlace<T>(this IList<T> source)
{
if (source == null) throw new ArgumentNullException("source");
var rng = new Random();
for (int i = 0; i < source.Count - 1; i++)
{
int j = rng.Next(i, source.Count);
T temp = source[j];
source[j] = source[i];
source[i] = temp;
}
}
I Think this solution faster to process, because you will get your itens randomly and your collection position will be preserved to future use.
namespace MyNamespace
{
public static class MyExtensions
{
public static T GetRandom<T>(this List<T> source)
{
Random rnd = new Random();
int index = rnd.Next(0, source.Count);
T o = source[index];
return o;
}
}
}
Steps:
Create your Static Class to Identify your extensions
Create you Extension Method (must be static)
Process your data.

Categories

Resources