Deleting A Specified Element In An Array Using Random Class - c#

class Check
{
public static void Main()
{
int[] arr1 = new int[] { 1, 2, 3 };
Console.WriteLine("The Number That Left Us Is");
Random rnd = new Random();
int r = rnd.Next(arr1.Length);
int Left = (arr1[r]);
Console.WriteLine(Left);
}
}
If 2 is generated i want the 2 to be removed and the remaining i have to be left with should be 1 and 3.
Can anyone help. Can it be done in array.

Arrays can not be re-sized, one you set them they are that size forever.
The "best" option is use a List<int> instead of an int[]
class Check
{
public static void Main()
{
List<int> arr1 = List<int>int[] { 1, 2, 3 };
Console.WriteLine("The Number That Left Us Is");
Random rnd = new Random();
int r = rnd.Next(arr1.Length);
int Left = (arr1[r]);
arr1.RemoveAt(r);
Console.WriteLine(Left);
}
}
To actually create a new array of one size smaller will take more code.
class Check
{
public static void Main()
{
int[] arr1 = int[] { 1, 2, 3 };
Console.WriteLine("The Number That Left Us Is");
Random rnd = new Random();
int r = rnd.Next(arr1.Length);
int Left = (arr1[r]);
int oldLength = arr1.Length;
arrTmp = arr1;
arr1 = new int[oldLength - 1];
Array.Copy(arrTmp, arr1, r);
Array.Copy(arrTmp, r+1, arr1, r, oldLength - r - 1);
Console.WriteLine(Left);
}
}
You mention "You gotta stick with the arrays", it is VERY easy to turn the list in to an array
class Check
{
public static void Main()
{
List<int> arr1 = List<int>int[] { 1, 2, 3 };
Console.WriteLine("The Number That Left Us Is");
Random rnd = new Random();
int r = rnd.Next(arr1.Length);
int Left = (arr1[r]);
arr1.RemoveAt(r);
Console.WriteLine(Left);
SomeFunctionThatTakesAnArrayAsAnArgument(arr1.ToArray());
}
}

Arrays cannot be resized, if you want to remove items use a List<T>.
However, you can create a new one. If you want to keep all items but one at the random index:
arr1 = arr1.Where((i, index) => index != r).ToArray();
With a list you can use RemoveAt which is more efficient than creating arrays:
var list = new List<int> { 1, 2, 3 };
list.RemoveAt(r);

Arrays can't be dynamically resized in .NET, so you can't really 'remove' an item from an array (you could set it to 0, but I don't think that's what you want).
Try using a List<int> instead:
List<int> list = new List<int>() { 1, 2, 3 };
Console.WriteLine("The Number That Left Us Is");
Random rnd = new Random();
int r = rnd.Next(list.Count);
int Left = (list[r]);
list.Remove(Left);
Console.WriteLine(Left);

Try to following it removes the item from the list and creates a new array without the specific item.
static void Main(string[] args)
{
int[] arr1 = new int[] { 1, 2, 3 };
Console.WriteLine("The Number That Left Us Is");
Random rnd = new Random();
int r = rnd.Next(arr1.Length);
// Create a new array except the item in the specific location
arr1 = arr1.Except(new int[]{arr1[r]}).ToArray();
int Left = (arr1[r]);
Console.WriteLine(Left);
}

Related

Random index of a value in an array

In my program, I have a function that finds the nearest index to an integer.
var indexWinnder = Array.IndexOf(scoreArray, nearestScore)
But the way that Array.IndexOf works is it finds the first match and uses that. I want a random index. Not the first. not the last. Is there any way I can do this?
There is no built-in method for that, but you could use your own method instead. My example uses a generic version of possible implementation.
class Program
{
static void Main(string[] args)
{
var arr = new int[] { 1, 2, 3, 1, 1, 5, 2, 6, 1 };
var randomIndex = RandomIndexOf(arr, 1);
Console.WriteLine(randomIndex);
Console.ReadKey();
}
static int RandomIndexOf<T>(ICollection<T> arr, T element)
{
var indexes = arr.Select((x, i) => new { Element = x, Index = i })
.Where(x => element.Equals(x.Element))
.Select(x => x.Index)
.ToList();
if (indexes.Count == 0) // there is no matching elements
{
return -1;
}
var rand = new Random();
var randomIndex = rand.Next(0, indexes.Count);
return indexes[randomIndex];
}
}
Maybe something like this is what you want:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
int[] sampleArray = new int[] { 1, 2, 3, 2, 1, 3, 1, 2, 3 };
var indices = getAllIndices(sampleArray, i => i == 2);
var rnd = new Random();
var i = rnd.Next(0, indices.Count());
var randomIndex = indices.ElementAt(i);
Console.WriteLine(randomIndex);
Console.ReadLine();
}
static IEnumerable<int> getAllIndices(int[] array, Predicate<int> predicate)
{
for (var i = 0; i < array.Length; i++)
{
if (predicate(array[i]))
yield return i;
}
}
}
HTH
Update
Don't forget to check for empty arrays, null arguments etc.
I dont know if i understood your problem right but if u just want a random index you could write a method and use:
Random rnd = new Random();
int index = rnd.Next(MinValue, MaxValue); // e.g: MinValue: 0, MaxValue: Length of the Array
and then just use that index as the array index.
Random isnt the best option if u really want a random one because it follows a specific pattern that will occur again and again and again. If u want something even more Random you could look into
RNGCryptoServiceProvider: https://www.dotnetperls.com/rngcryptoserviceprovider.
Hope this helps!

c# Select N elements from list uniformly without shuffle

I want to select K elements uniformly from a list of N elements without shuffling a list. So the algorithm should always produce the same result.
E.g.
int N = 100;
List<int> myList = Enumerable.Range(0, N-1).ToList();
int K = 20;
Here i expect the result: 0, 5, 10, 15, 20, ...
E.g. if K == 50 I expect: 0, 2, 4, 6, 8, ...
But I don't know how to solve it if e.g. K = 53? I still want to take uniformly elements from the list, but in this case we can't simply take each second element from the list. Simple approach would be to shuffle elements and take first K elements from the list, order again the list but in that case the result of algorithm would each time produce different result and i need each time the same result.
Any help would be appreciated.
Find what the indices would be if they were all equidistant, and round to the nearest integer.
int N = 100;
List<int> myList = Enumerable.Range(0, N).ToList();
double K = 53;
List<int> solutions=new List<int>();
for (int i=1;i<=K;i++)
{
solutions.Add(myList[(int)Math.Round(i*(N/K)-1)]);
}
Console.WriteLine(solutions.Count);
Console.WriteLine(string.Join(", ", solutions));
See a sample at: DEMO
EDIT: Math.Floor works better than Math.Round as Math.Round gives the wrong solution to N=5, K=3:
Math.Round->1,2,4
Math.Floor->0,2,4
See a sample at: DEMO2
This problem is exactly same as line drawing algorithm: https://en.wikipedia.org/wiki/Line_drawing_algorithm
In your case, you want to draw a line from (0, 0) to (20, 52)
You could still shuffle the list. Please see the follwing example
var n = 100;
var k = 53;
var originalList = GetListWithNElements(n);
var shuffledList = ShuffleList(originalList);
var firstKElements = GetFirstKElements(k, shuffledList);
[...]
List<int> GetListWithNElements(int n)
{
return Enumerable.Range(0, n-1).ToList();
}
List<int> ShuffleList(List<int> originalList)
{
List<int> copy = originalList.ToList();
List<int> result = new List<int>();
Random randomGenerator = new Random(314159);
while(copy.Any())
{
int currentIndex = randomGenerator.Next(copy.Count);
result.Add(copy[currentIndex]);
copy.RemoveAt(currentIndex);
}
return result;
}
List<int> GetFirstKElements(int k, List<int> shuffledList)
{
return shuffledList.Take(k).ToList();
}
Random is initialized with a constant seed and hence will produce the very same sequence of "random" values each time, hence you will take the same elements each time.
Try following :
static void Main(string[] args)
{
const int N = 100;
{
List<int> myList = Enumerable.Range(0, N - 1).ToList();
int seed = 5;
int numberOfItems = 50;
List<int> results = TakeNItems(myList, seed, numberOfItems);
}
}
static List<int> TakeNItems(List<int> data, int seed, int numberOfItems)
{
Random rand = new Random(seed);
return data.Select((x,i) => new { x = x, index = i, rand = rand.Next()})
.OrderBy(x => x.rand)
.Take(numberOfItems)
.OrderBy(x => x.index)
.Select(x => x.x)
.ToList();
}

Random number generator choosing only between given few numbers in C#

I know how to choose random numbers between two numbers. However I don't know how to make it to choose a random number that I tell it.
This is what I am trying to do. I have 5 integers.
int Hamburger = 5;
int Sandwich = 7;
int ChickenSalad = 10;
int Pizza = 15;
int Sushi = 20;
5,7,10,15,20 are the prices of each food and I want to make it so that it would choose a random number from these chosen numbers. 5,7,10,15,20.
I am new to C# so I don't really know much about this. I found this
randomNoCorss = arr[r.Next(arr.Length)];
in another post but I don't understand it and I don't know how I can put it in my code.
You have to create an array of your possible values and then randomly generate an index for that array:
int Hamburger = 5;
int Sandwich = 7;
int ChickenSalad = 10;
int Pizza = 15;
int Sushi = 20;
Random r = new Random();
var values = new[] { Hamburger, Sandwich, ChickenSalad, Pizza, Sushi };
int result = values[r.Next(values.Length)];
What this does is it takes all of your given values and places them inside an array. It then generates a random integer between 0 and 4 and uses that integer to get a value from the array using the generated integer as the array's index.
Full code is:
Random r = new Random();
int[] priceArray = new int[] { 5, 7, 10, 15, 20 };
int randomIndex = r.Next(priceArray.Length);
int randomPrice = priceArray[randomIndex];
You need to add your values in an array and then you can choose a random number from that array
int[] myNumbers = new int[] { 5, 7, 10, 15, 20 };
var random = new Random();
var numberResult = myNumbers[random.Next(5)];
You can do this in LINQ:
int[] intArray = new int[] { 5, 7, 10, 15, 20 };
int result = intArray.OrderBy(n => Guid.NewGuid()).Select(x => x).Take(1)
.SingleOrDefault();
The result will be random based on your declared array of integers in variable intArray.
Or you can do this by getting the random index of your array:
int[] intArray = new int[] {5, 7, 10, 15, 20 };
Random rndom = new Random();
int index = rndom.Next(0, intArray.Length - 1); //Since int array always starts at 0.
int intResult = intArray[index];
Let me know if you need more clarifications.

How to generate unique random integers that do not duplicate

I have created a short program that creates 3 random integers between 1-9 and stores them in an array, however, I would not like any of them to repeat, that is, I would like each to be unique. Is there an easier way to generate 3 unique integers other than having to iterate through the array and comparing each integer to each other? That just seems so tedious if I were to increase my array to beyond 3 integers.
This is my code to generate 3 random numbers. I saw other code in Java, but I thought maybe C# has a easier and more efficient way to do it.
var number = new Numbers[3];
Random r = new Random();
for ( int i = 0; i < number.Length; i++)
{
number[i] = new Numbers(r.Next(1,9));
}
Console.WriteLine("The Three Random Numbers Are:");
foreach(Numbers num in number)
{
Console.WriteLine("{0}", num.Number);
}
I would do something like this:
var range = Enumerable.Range(1, 8);
var rnd = new Random();
var listInts = range.OrderBy(i => rnd.Next()).Take(3).ToList();
You could make an array or a list of the numbers that might be generated, e.g. 0, 1, 2, 3. Then you generate a number from 0 to this list's length, e.g. 2 and pick list[2] so for the next time you only have 0, 1, 3 in your list.
It takes longer to generate it, especially for long lists but it doesn't repeat numbers.
using System;
using System.Collections.Generic;
public class Test
{
static Random random = new Random();
public static List<int> GenerateRandom(int count)
{
// generate count random values.
HashSet<int> candidates = new HashSet<int>();
// top will overflow to Int32.MinValue at the end of the loop
for (Int32 top = Int32.MaxValue - count + 1; top > 0; top++)
{
// May strike a duplicate.
if (!candidates.Add(random.Next(top))) {
candidates.Add(top);
}
}
// load them in to a list.
List<int> result = new List<int>();
result.AddRange(candidates);
// shuffle the results:
int i = result.Count;
while (i > 1)
{
i--;
int k = random.Next(i + 1);
int value = result[k];
result[k] = result[i];
result[i] = value;
}
return result;
}
public static void Main()
{
List<int> vals = GenerateRandom(10);
Console.WriteLine("Result: " + vals.Count);
vals.ForEach(Console.WriteLine);
}
}
Grate explanation and answers from here
Source http://ideone.com/Zjpzdh

How to generate random INT that cannot be a value in a List<int>?

I'm trying to do the following.
Let's say I have a List, and I want to generate a new int in a specific range, but the value cannot be already defined in the List.
List<int> PredefinedIntsList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
int NewRandomValue = rnd.Next(0, 10);
rnd.Next (obviously) comes up with 1, 3, 4, 8 or 9. But I ONLY want it to return 2, 5, 6, 7 or 10.
Any ideas?
As always, LINQ is your friend:
[TestMethod]
public void RandomTest()
{
var except = new[] {1, 2, 3, 5};
GetRandomExcept(1, 5, except).Should().Be(4);
}
private static int GetRandomExcept(int minValue, int maxValue, IEnumerable<int> except)
{
return GetRandoms(minValue, maxValue).Except(except).First();
}
private static IEnumerable<int> GetRandoms(int minValue, int maxValue)
{
var random = new Random();
while (true) yield return random.Next(minValue, maxValue);
}
Just keep in mind that you never should call GetRandoms().ToArray() or .Max() or .OrderBy() and so on, because you will get an endless loop and generate randoms forever.
What you can do though, is call GetRandoms().Take(10).ToArray() to get the next 10 random integers in an array.
Try examining if you can use the contains() method of List class... Simple solution would be to just generate values and checking contains and rejecting values that are already in the List until you get a value that is not. Also it might be more appropriate to use the Set Class because a set can not contain two elements that are equal.
What you need to do sample from other set. Lets say P is your predefinedIntsList and A is {1,2...9}.
You need to create a list, N = A-P. You will randomly sample from this set of numbers. It can be written more elegantly I suppose but see below example.
class Program
{
static void Main(string[] args)
{
List<int> predefinedIntsList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
List<int> newIntsList = new List<int>();
int upperBound = 10;
for (int i = 0; i < upperBound; i++)
{
if (!predefinedIntsList.Contains(i))
{
newIntsList.Add(i);
}
}
for (int i = 0; i < 20; i++)
{
int newRandomValueIndex = rnd.Next(0, newIntsList.Count);
int newRandomValue = newIntsList[newRandomValueIndex];
Console.WriteLine(newRandomValue);
}
}
}
Output
2
0
6
7
5
5
5
7
0
7
6
6
5
5
5
0
6
7
0
7
rnd.Next (obviously) comes up with 1, 3, 4, 8 or 9. But I ONLY want it
to return 2, 5, 6, 7 or 10.
Obviously not, it will return value that is either 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9 :P. If you're looking to include 10, and not 0, you want .Next(1, 11)
There are two choices that can work: either try generating values until you succeed, or if the range is small enough, generate the range, mark elemens that can't be picked, and sort them to last ones, and then pick random between [0..possibleToPickElementsCount]
The first approach would look something like this:
public static class RandomExtensions
{
public static int Next(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
// this will crash if values contains
// duplicate values.
var dic = values.ToDictionary(val => val);
// this can go into forever loop,
// think about this a bit.
for(;;){
var randomNumber= random.Next(minInclusive, maxExclusive);
if(!dic.ContainsKey(randomNumber))
return randomNumber;
}
}
}
The second approach is this, however it's only to give you an idea:
public static class RandomExtensions
{
class NormalizedPair
{
public int Value {get;set;}
public PairStatus Status {get;set;}
public NormalizedPair(int value){
Value = value;
}
public enum PairStatus {
Free,
NotFree
}
}
private static Random _internalRandom = new Random();
public static int Next(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
var elements = maxExclusive - minInclusive;
var normalizedArr = new NormalizedPair[elements];
var normalizedMinInclusive = 0;
var normalizedMaxExclusive = maxExclusive - minInclusive;
var normalizedValues = values
.Select(x => x - minInclusive)
.ToList();
for(var j = 0; j < elements; j++)
{
normalizedArr[j] = new NormalizedPair(j){
Status = NormalizedPair.PairStatus.Free
};
}
foreach(var val in normalizedValues)
normalizedArr[val].Status = NormalizedPair.PairStatus.NotFree;
return normalizedArr
.Where(y => y.Status == NormalizedPair.PairStatus.Free) // take only free elements
.OrderBy(y => _internalRandom.Next()) // shuffle the free elements
.Select(y => y.Value + minInclusive) // project correct values
.First(); // pick first.
}
}
Or, if you're fan of sets:
public static int Next2(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
var rangeSet = new HashSet<int>(
Enumerable.Range(
minInclusive,
maxExclusive - minInclusive));
// remove gibberish
rangeSet.ExceptWith(new HashSet<int>(values));
// this can be swapped out with
// yates shuffle algorithm
return rangeSet.OrderBy(x => _internalRandom.Next())
.First();
}
Rather than write logic to determine whether the random number has already been selected I prefer to generate a second list with the items in a random order.
That is easy to do with LINQ
var originalList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
var secondList = originalList.OrderBy(x=>rnd.NextDouble());
The call to rnd.NextDouble returns a random seed that is used by the OrderBy method to sort each int value.
When I need to run thought the randomized items more than once, with a new sort order each time I walk the list, I will use a Queue to store the items. Then dequeue the items as needed. When the queue is empty it's time to refill.
private Queue<int> _randomizedItems;
private void RandomTest()
{
var originalList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
var temp = originalList.OrderBy(r=>rnd.NextDouble());
_randomizedItems = new Queue<int>(temp);
while (_randomizedItems.Count >0)
{
MessageBox.Show(_randomizedItems.Dequeue().ToString());
}
}

Categories