Random r = new Random();
int randomvalue = r.Next(1,20);
*
*
if(randomvalue == 1) something
if(randomvalue == 2) something
*
*
if(randomvalue == 19) something
What is the best way to make that randomvalue without repeat? Btw: Its WPF, not console.
Try something like below :
Random randomInstance = new Random();
List<int> NumList = new List<int>();
NumList.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30 });
int index = randomInstance.Next(0, NumList.Count - 1);
int randomNumber = NumList[index];
NumList.RemoveAt(index);
// This will work
class Program
{
static void Main(string[] args)
{
List<int> i = new List<int>(new int[] { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20});
List<int> r;
r = ShuffleList(i);
}
private static List<E> ShuffleList<E>(List<E> unshuffledList)
{
List<E> sList = new List<E>();
Random r = new Random();
int randomIndex = 0;
while (unshuffledList.Count > 0)
{
randomIndex = r.Next(0, unshuffledList.Count);
sList.Add(unshuffledList[randomIndex]);
unshuffledList.RemoveAt(randomIndex); //remove so wont be added a second time
}
return sList; //return the new shuffled list
}
}
Try this:
var rnd = new Random();
var shuffled =
Enumerable
.Range(1, 20)
.OrderBy(x => rnd.Next())
.ToArray();
using System;
using System.Collections;
using System.Collections.Generic;
namespace SOFAcrobatics
{
public static class Launcher
{
public static void Main ()
{
// 1 to 20 without duplicates
List<Int32> ns = new List<Int32>();
Random r = new Random();
Int32 ph = 0;
while (ns.Count < 20)
{
while (ns.Contains (ph = r.Next(1, 21))) {}
ns.Add(ph);
}
// ns is now populated with random unique numbers (1 to 20)
}
}
}
You need to store random value is the only way to make it unique.
Try this:
Random r = new Random();
public List<int> randomList = new List<int>();
int randomvalue = 0;
Public void newNumber()
{
randomvalue = r.Next(0, 20);
if (!randomList.Contains(randomvalue))
{
randomList.Add(randomvalue);
if(randomvalue == 1)
//do something
if(randomvalue == N)
// do something
}
}
It is not clear what you mean by repeat. If you don't want to see the same number in a row then just keep a hash table or Dictionary<int,int> which keeps the last integer that came out. Then check if the next number is same with last number. If not, remove last number from dictionary and put the current one. If they are same then request another random integer from Random.
var myDictionary = new Dictionary<int,int>;
var randomvalue = r.Next(1,20);
while(myDictionary.ContainsKey(randomvalue))
{
randomvalue = r.Next(1,20);
}
myDictionary.Clear();
myDictionary.Add(randomvalue, 123); //123 is just a number. Doesn't matter.
This guarantees that two same integer will never come consecutively.
NOTE:: Other answers are creative, but "know your data structure". Don't use a list for look up. Hash is what we use for it.
Related
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!
12,13,14,15,16,19,19,19,19
to
12,19,13,19,14,19,15,19,16
Hey all. Can anyone point me to clues/samples on how to distribute the first array of Int32 values, where a bunch of 19 values were appended, to the second where the 19 values are fairly evenly interspersed in the array?
I am not looking for a random shuffling, as in this example #19 could still appear consecutively if there was randomization. I want to make sure that #19 is placed in between the other numbers in a predictable pattern.
The use-case for this is something like teams taking turns presenting a topic: teams 12-16 each present once and then team #19 shows up but should not show their topic four times in a row, they should show their topic in between the other teams.
Later, if twelve values of 7 are added to the array, then they will also have to be evenly distributed into the sequence as well, the array would be 21 elements but the same rule that neither #19 or #7 should have consecutive showings.
I thought there might be something in Math.NET library that would do this, but I did not find anything. Using C# on .NET Framework 4.7.
Thanks.
Details on the following method that evenly (mostly) distributes the duplicates in your list. Duplicates can be anywhere in your list, they will be distributed.
Create a dictionary of all numbers and keep track of the number of times they appear in the list
Use a new list without any duplicates. For Each number that has duplicates, spread it over the size of this new list. Each time the distribution is even.
public static List<int> EvenlyDistribute(List<int> list)
{
List<int> original = list;
Dictionary<int, int> dict = new Dictionary<int, int>();
list.ForEach(x => dict[x] = dict.Keys.Contains(x) ? dict[x] + 1 : 1);
list = list.Where(x => dict[x] == 1).ToList();
foreach (int key in dict.Where(x => x.Value > 1).Select(x => x.Key))
{
int iterations = original.Where(x => x == key).Count();
for (int i = 0; i < iterations; i++)
list.Insert((int)Math.Ceiling((decimal)((list.Count + iterations) / iterations)) * i, key);
}
return list;
}
Usage in main:
List<int> test = new List<int>() {11,11,11,13,14,15,16,17,18,19,19,19,19};
List<int> newList = EvenlyDistribute(test);
Output
19,11,13,19,14,11,19,15,16,19,11,17,18
Here's how to do this.
var existing = new[] { 12, 13, 14, 15, 16 };
var additional = new [] { 19, 19, 19, 19 };
var lookup =
additional
.Select((x, n) => new { x, n })
.ToLookup(xn => xn.n * existing.Length / additional.Length, xn => xn.x);
var inserted =
existing
.SelectMany((x, n) => lookup[n].StartWith(x))
.ToArray();
This gives me results like 12, 19, 13, 19, 14, 19, 15, 19, 16.
The only thing that this won't do is insert a value in the first position, but otherwise it does evenly distribute the values.
In case random distribution is enough the following code is sufficient:
static void MixArray<T>(T[] array)
{
Random random = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
T value = array[k];
array[k] = array[n];
array[n] = value;
}
}
For instance:
int[] input = new int[]{12,13,14,15,16,19,19,19,19};
MixArray<int>(input);
In case you require precise evenly distribution while retaining the order of the elements, to following code will do the job:
public static T[] EvenlyDistribute<T>(T[] existing, T[] additional)
{
if (additional.Length == 0)
return existing;
if (additional.Length > existing.Length)
{
//switch arrays
T[] temp = additional;
additional = existing;
existing = temp;
}
T[] result = new T[existing.Length + additional.Length];
List<int> distribution = new List<int>(additional.Length);
double ratio = (double)(result.Length-1) / (additional.Length);
double correction = -1;
if (additional.Length == 1)
{
ratio = (double)result.Length / 2;
correction = 0;
}
double sum = 0;
for (int i = 0; i < additional.Length; i++)
{
sum += ratio;
distribution.Add(Math.Max(0, (int)(sum+correction)));
}
int existing_added = 0;
int additional_added = 0;
for (int i = 0; i < result.Length; i++)
{
if (additional_added == additional.Length)
result[i] = existing[existing_added++];
else
if (existing_added == existing.Length)
result[i] = additional[additional_added++];
else
{
if (distribution[additional_added] <= i)
result[i] = additional[additional_added++];
else
result[i] = existing[existing_added++];
}
}
return result;
}
For instance:
int[] existing = new int[] { 12, 13, 14, 15, 16};
int[] additional = new int[] { 101, 102, 103, 104};
int[] result = EvenlyDistribute<int>(existing, additional);
//result = 12, 101, 13, 102, 14, 103, 15, 104, 16
I want to give even number cards to player 1 and odd number cards to player 2 . If any of you guys could do it that will be really appreciated thank you. I know how to do this with array, but I am not sure with list.
class MatchDeck
{
private const int NUMBER_OF_CARDS = 36;
private Random r = new Random();
List<MatchCard> deck = new List<MatchCard>();
public MatchDeck(){ }
public void createDeck()
{
int[] number = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };
string[] suits = { "R[]", "R0", "B0", "B[]" };//these are suits i just made up
// deck = new MatchCard[NUMBER_OF_CARDS];
foreach (var suit in suits)
{
for (int num = 2; num <= 10; num++)
{
deck.Add(new MatchCard(num, suit));
// Console.WriteLine(deck[i++].toString());
}
}
foreach(MatchCard card in deck)
{
Console.WriteLine(card.Number + " " + card.Suit);
}
}
public void Shuffle()
{
Random ran = new Random();
int n = deck.Count;
while (n > 1)
{
n--;
int k = ran.Next(n + 1);
MatchCard value = deck[k];
deck[k] = deck[n];
deck[n] = value;
}
foreach (MatchCard card in deck)
{
Console.WriteLine(card.Number + " " + card.Suit);
}
}
public void deal()
{
List<MatchCard> player1 = new List<MatchCard>();
List<MatchCard> player2 = new List<MatchCard>();
}
}
What you trying to achieve can be done by using a loop or Linq.
If you want to loop through your array or List the condition would be
if(deck[i] % 2 == 0) for even numbers. The opposite for odd. But this is already mentioned in the comment of #misha130.
May be you want to read about the Linq possibilities that List offers.
Here is a post that gives you a nice example how to extract values from a List according to a condition (like in your case). To get to know the class List and its methods please read the documentation
These two particular methods would be of your main interest in this case: FindAll && Where
Now you should have all the necessary information to solve your problem. Good luck. Comment if you are still stuck.
I've refactored your code so to what you're after. The key part relating to dealing the cards is the .Where((x, n) => n % 2 == 0)& .Where((x, n) => n % 2 == 1) code.
public class MatchDeck
{
private Random r = new Random();
List<MatchCard> deck = null;
public MatchDeck()
{
int[] number = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };
string[] suits = { "R[]", "R0", "B0", "B[]" };
deck = number.SelectMany(n => suits, (n, s) => new MatchCard(n, s)).ToList();
}
public void Shuffle()
{
deck = deck.OrderBy(x => r.Next()).ToList();
}
public void Deal()
{
List<MatchCard> player1 = deck.Where((x, n) => n % 2 == 0).ToList();
List<MatchCard> player2 = deck.Where((x, n) => n % 1 == 0).ToList();
}
}
I have a list of numbers and I want to know which combination of the numbers in the list has the closest sum to a specific number(Target).( if there are many combinations, finding one is enough)
I searched a lot and know that there are lots of solutions here to find the combinations that their sum is equal to specific number, but there were no solution to find the greatest close to that number.
I also wrote a piece of code that loops from zero to "Target" to find the biggest sum, but as this process is so time consuming as it must be calculated for 100,000 lists, i wonder if there is more efficient way using preferably linq.
var List1 = new int[] { 5, 10, 15, 20, 25, 30, 35, 40, 45 };
var target = 40;
int MaxViewers = Convert.ToInt32(txtNoRecordsToAdd.Text);
for (int UserNo = 1; UserNo <= MaxViewers; UserNo++)
{
for (int No = 1; No <= target; No++)
{
var matches = from subset in MyExtensions.SubSetsOf(List1)
where subset.Sum() == target
select subset;
}
}
public static class MyExtensions
{
public static IEnumerable<IEnumerable<T>> SubSetsOf<T>(this IEnumerable<T> source)
{
if (!source.Any())
return Enumerable.Repeat(Enumerable.Empty<T>(), 1);
// Grab the first element off of the list
var element = source.Take(1);
// Recurse, to get all subsets of the source, ignoring the first item
var haveNots = SubSetsOf(source.Skip(1));
// Get all those subsets and add the element we removed to them
var haves = haveNots.Select(set => element.Concat(set));
// Finally combine the subsets that didn't include the first item, with those that did.
return haves.Concat(haveNots);
}
}
Hello let's check a tricky way to achieve this,
var List1 = new int[] { 5, 10, 15, 20, 25, 30, 35, 40, 45 };
var target = 40;
int MaxViewers = Convert.ToInt32(txtNoRecordsToAdd.Text);
var closestSubSet = MyExtensions.SubSetsOf(List1)
.Select(o=> new{ SubSet = o, Sum = o.Sum(x=> x)})
.Select(o=> new{ SubSet = o.SubSet, Sum = o.Sum, FromTarget = (target - o.Sum >= 0 ? target - o.Sum : (target - o.Sum) * -1 ) })
.OrderBy(o=> o.FromTarget).FirstOrDefault();
I know it's tricky i made the 2nd select for some performance reasons (Not Calling Sum Multiple Times But Use It). This should find the closest sum to the target you specify ^^ Have Fun
Optimization:
var List1 = new int[] { 5, 10, 15, 20, 25, 30, 35, 40, 45 };
var target = 40;
int MaxViewers = Convert.ToInt32(txtNoRecordsToAdd.Text);
int minClosestTargetRequired = 0;
int closestSum = int.maxValue;
int closestSetIndex = -1;
var subsets = MyExtensions.SubSetsOf(List1);
for(var c = 0 ; c < subsets.Count() ; c++)
{
int currentSum = subsets[c].Sum(o=> o);
if(currentSum < closestSum)
{
closestSum = currentSum;
closestSetIndex = c;
}
if(closestSum <= minClosestTargetRequired)
break;
}
Console.WriteLine("Closest Sum Is {0} In Set Index {1},closestSum,closestSetIndex);
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());
}
}