c# extension methods for generic array - c#

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

Related

Should a input object be cloned if it is the return value?

when you have a method such as
public static T[] GetZeroArrayIfNot<T>(this T[] array)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
else if (array.Length == 0)
{
return //array or (array.Clone() as T[])?
}
return new T[0];
}
or something along the lines of
public static int HundredOrLess(int num)
{
if (num <= 100)
{
return //num or ((int num2 = num) => (return num2)) doubt this one matters.
}
return 100;
}
or
public static List<T> ReturnItself<T>(List<T> list)
{
return //list or (list.Clone() as List<T>);
}
if the input is being returned, sins nothing changed, can it be returned just as itself or, should it be cloned and returned as the return type?
Since your method signature is this:
public static T[] RemoveFirstElement<T>(this T[] array)
I would assume that this would always return a new array. Because you would always have to write:
var myArray = SomeArray.RemoveFirstElement();
You would not expect that myArray would now be pointing to exactly the same object as SomeArray. If you wanted it to always operate on the existing array, your method signature would be:
public static void RemoveFirstElement<T>(this T[] array)
So that writing:
var myArray = SomeArray.RemoveFirstElement();
Would result in a compile-time error. And it would be apparent that seeing:
SomeArray.RemoveFirstElement();
Would be operating in-place.
An array with zero length is immutable, so it can be returned safely without cloning.
To remove an element from a non-empty array, anyway it needs to be cloned because the length of array cannot be changed.
public static T[] RemoveFirstElement<T>(this T[] array)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
else if (array.Length == 0)
{
return array;
}
else
{
return array.Skip(1).ToArray();
}
}
This is my opinion regarding the new examples:
public static T[] GetZeroArrayIfNot<T>(this T[] array)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
else if (array.Length == 0)
{
return array;
// because the name of the method implies that a zero-length array
// should be treated differently than a non-zero-length array
}
return new T[0];
}
public static int HundredOrLess(int num)
{
if (num <= 100)
{
return num;
// It doesn't matter. The caller is not affected either way
// because num is an immutable value type passed by value
}
return 100;
}
public static List<T> ReturnItself<T>(List<T> list)
{
return list; // Because the method name says so
}

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

C# Lists reference with two?

I need 2 lists which are separate and one list containing the items of these two lists.
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
List<int> list3 = list1 & list2
When I add some integers in list1, I would like them to appear in list3 as well.
I want the same behavior when a new item is added into list2.
A reference of more than one lists.
Is this possible?
No, you can't do that with List<T> directly. However, you could declare:
IEnumerable<int> union = list1.Union(list2);
Now that will be lazily evaluated - every time you iterate over union, it will return every integer which is in either list1 or list2 (or both). It will only return any integer once.
If you want the equivalent but with concatenation, you can use
IEnumerable<int> concatenation = list1.Concat(list2);
Again, that will be lazily evaluated.
As noted in comments, this doesn't expose all the operations that List<T> does, but if you only need to read from the "combined integers" (and do so iteratively rather than in some random access fashion) then it may be all you need.
Is it possible?
Not with List since it's a static data structure - however you could use a query that is the concatenation of the two lists. Then whenever you enumerate the query it will show the current contents:
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
IEnumerable<int> list3 = list1.Concat(list2);
But as soon as you materialize the query into a data structure (by calling ToList, ToArray, etc.) the contents are static and will not update if one of the underlying lists updates.
No. You can create your own custom type that exposes methods similar to what a List<T> does (an indexer, Add, Remove methods, etc.), possibly even implementing IList<T>, but it wouldn't be a List<T>.
public class CompositeList<T> : IList<T>
{
private IList<IList<T>> lists;
public CompositeList(IList<IList<T>> lists)
{
this.lists = lists;
}
public CompositeList(params IList<T>[] lists)
{
this.lists = lists;
}
public int IndexOf(T item)
{
int globalIndex = 0;
foreach (var list in lists)
{
var localIndex = list.IndexOf(item);
if (localIndex >= 0)
return globalIndex + localIndex;
else
globalIndex += list.Count;
}
return -1;
}
public void Insert(int index, T item)
{
//note that there is an ambiguity over where items should be inserted
//when they are on the border of a set of lists.
foreach (var list in lists)
{
//use greater than or equal instead of just greater than to have the inserted item
//go in the later of the two lists in ambiguous situations,
//rather than the former.
if (index > list.Count)
index -= list.Count;
else
{
list.Insert(index, item);
return;
}
}
//TODO deal with having no lists in `lists`
//TODO deal with having only empty lists in `lists`
throw new IndexOutOfRangeException();
}
public void RemoveAt(int index)
{
foreach (var list in lists)
{
if (index > lists.Count)
index -= list.Count;
else
list.RemoveAt(index);
}
throw new IndexOutOfRangeException();
}
public T this[int index]
{
get
{
foreach (var list in lists)
{
if (index > lists.Count)
index -= list.Count;
else
return list[index];
}
throw new IndexOutOfRangeException();
}
set
{
foreach (var list in lists)
{
if (index > lists.Count)
index -= list.Count;
else
list[index] = value;
}
throw new IndexOutOfRangeException();
}
}
public void Add(T item)
{
if (!lists.Any())
lists.Add(new List<T>());
lists[lists.Count - 1].Add(item);
}
public void Clear()
{
foreach (var list in lists)
list.Clear();
}
public bool Contains(T item)
{
return lists.Any(list => list.Contains(item));
}
public void CopyTo(T[] array, int arrayIndex)
{
if (array.Length - arrayIndex - Count < 0)
throw new ArgumentException("The array is not large enough.");
int iterations = Math.Min(array.Length, Count);
for (int i = arrayIndex; i < iterations; i++)
array[i] = this[i];
}
public int Count
{
get { return lists.Sum(list => list.Count); }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
foreach (var list in lists)
{
if (list.Remove(item))
return true;
}
return false;
}
public IEnumerator<T> GetEnumerator()
{
return lists.SelectMany(x => x).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

How to access random item in list?

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

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