Divide sequence elements into pairs - c#

I have a sequence of 16 elements: 1,2,3,..., 16 ( or 2*n elements). Sequence elements always goes from 1 to length(sequence) that is sequence of 4 elements is 1,2,3,4.
Edit: first sequence element is always = 1, second sequence element = 2, third sequence element = 3 and so on. It's for a game "find a pair pictures".
I want to write an algorithm which divide elements into pairs. For Example,
1-15
2-16
3-13
4-9
5-14
6-10
7-11
8-12
PS: no linq please :) vs2005
Edit: As I can see, my question is so simple so no one can answer it :) Or everybody afraid something ?

Without a selection criteria, just take every other one.....
var result = new List<Tuple<int,int>>();
for (int i = 1; i < size; i+=2 )
{
var pair = new Tuple.Create(i,i+1);
result.Add(pair);
}

What about this?
class Program
{
static void Main(string[] args)
{
int size = 8;
List<int> tmpList = new List<int>();
for (int i = size; i <= size * 2; i++)
{
tmpList.Add(i);
}
List<Pair> result = new List<Pair>();
Random r = new Random();
for (int i = 1; i <= size; i++)
{
Pair pair = new Pair() { a = i, b = PopRandom(r, tmpList) };
result.Add(pair);
}
foreach (Pair p in result)
{
Console.WriteLine("{0} - {1}", p.a, p.b);
}
}
static private int PopRandom(Random r, List<int> list)
{
int i = r.Next(0, list.Count);
int result = list[i];
list.RemoveAt(i);
return result;
}
struct Pair
{
public int a;
public int b;
}
}
UPD: this was compiled successfully for .net 2.0 target platform
UPD 2: Random instance moved out from PopRandom()

Related

How does the size of IEnumerable get set? C#

I have some code that wasn't written by myself and I'm trying to use it to build a Poker ICM calculator program. This program takes an array of stack sizes and prize payouts and calculates each players prize equity.
The code works for 3 prizes but when I add a 4th prize I get an index out of bounds error because I'm trying to get permutation[3] when the object only contains indexes 0 to 2. The problem is I can't understand how the size of permuation gets set so I can't figure out how to adjust the code to work for higher numbers of prizes. I'd appreciate some help.
Below is a minimum working example with working and non-working code in the main method and a comment to indicate where the error occurs.
ICMCalculator.cs
class ICMCalculator
{
public double[] CalcEV(int[] structure, int[] chips)
{
//the probability of a players position
double[,] probabilitys = new double[structure.Length, chips.Length];
//the expected value of the player
double[] EVs = new double[chips.Length];
int[] players = new int[chips.Length];
for (int i = 0; i < players.Length; ++i)
players[i] = i;
IEnumerable<int[]> permutations;
for (int i = 0; i < structure.Length; ++i)
{
permutations = (new Permutation()).Enumerate(players, i + 2);
foreach (int[] permutation in permutations)
{
// OUT OF BOUNDS ERROR OCCURS HERE
probabilitys[i, permutation[i]] += CalcPermutationProbability(permutation, chips);
}
}
for (int i = 0; i < structure.Length; ++i)
{
for (int j = 0; j < chips.Length; ++j)
EVs[j] += probabilitys[i, j] * structure[i];
}
return EVs;
}
private double CalcPermutationProbability(int[] permutations, int[] chips)
{
double probability = 1.0F;
int chips_sum = chips.Sum();
for (int i = 0; i < permutations.Length; ++i)
{
probability *= System.Convert.ToDouble(chips[permutations[i]]) / System.Convert.ToDouble(chips_sum);
chips_sum -= chips[permutations[i]];
}
return probability;
}
}
Permutation.cs
class Permutation
{
public IEnumerable<T[]> Enumerate<T>(IEnumerable<T> nums, int length)
{
var perms = _GetPermutations<T>(new List<T>(), nums.ToList(), length);
return perms;
}
private IEnumerable<T[]> _GetPermutations<T>(IEnumerable<T> perm, IEnumerable<T> nums, int length)
{
if (length - perm.Count() <= 0)
{
yield return perm.ToArray();
}
else
{
foreach (var n in nums)
{
var result = _GetPermutations<T>(perm.Concat(new T[] { n }),
nums.Where(x => x.Equals(n) == false), length - perm.Count());
foreach (var xs in result)
yield return xs.ToArray();
}
}
}
}
Utils.cs
class Utils
{
public static string DoubleArrayToString(double[] doubles)
{
StringBuilder sb = new StringBuilder();
foreach (double dub in doubles)
{
sb.AppendLine(Utils.Format2DP(dub));
}
return sb.ToString().Trim();
}
}
Program.cs
static class Program
{
static void Main()
{
// THIS WORKS
ICMCalculator ev = new ICMCalculator();
int[] stacks = new int[] { 4500, 2700, 1800, 1000, 500 };
int[] prizes = new int[] { 84,36,18 };
int prizePool = prizes.Sum();
double[] equity = ev.CalcEV(prizes, stacks);
Console.WriteLine(Utils.DoubleArrayToString(equity));
// THIS THROWS INDEX ERROR
ev = new ICMCalculator();
stacks = new int[] { 4500, 2700, 1800, 1000, 500 };
prizes = new int[] { 84,36,18,9 };
prizePool = prizes.Sum();
equity = ev.CalcEV(prizes, stacks);
Console.WriteLine(Utils.DoubleArrayToString(equity));
}
}
To be clear, I believe that each 'permutation' should be the length of structure.Length. I don't want to avoid the out of bounds error by reducing the max value of i. I think I need to increase the size of each permuation to match structure.Length but I'm unable to figure out how to do this.
If resolved correctly, the code that currently fails should output the values: 50.82, 37.85, 29.16, 19.01, 10.15
I think the problem is in this line:
var result = _GetPermutations<T>(perm.Concat(new T[] { n }),
nums.Where(x => x.Equals(n) == false), length - perm.Count());
Instead, I think it should be
var result = _GetPermutations<T>(perm.Concat(new T[] { n }),
nums.Where(x => x.Equals(n) == false), length);
The problem here is that we are double-counting the length of the permutation found so far when we determine whether to stop further recursion.
The condition length - perm.Count() <= 0 (which can be simplified to perm.Count() >= length) is used to stop further calls to _GetPermutations if the permutation perm generated so far is long enough to be returned. This relies on the parameter length being the required length of the resulting permutations. However, by passing length - perm.Count() in the recursive call to _GetPermutations(), then we are reducing the value of length that inner calls to _GetPermutations() receive, causing them to stop the recursion early with permutations that are too short.

algorithm that is less than O(n2) time complexity [duplicate]

This question already has answers here:
Find two sum function in c#
(15 answers)
Closed 1 year ago.
I'm trying to modify this algorithm which is of complexity O(n2) to something quicker.
the algorithm is supposed to do the following
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Output: Because nums[0] + nums[1] == 9, we return [0, 1].
Any help is appreciated.
using System.Collections.Generic;
public class Solution
{
public int[] TwoSum(int[] nums, int target)
{
int[] output = new int[2];
for (int i = 0; i < nums.Length; i++)
{
for (int n = 0; n < nums.Length; n++)
{
if ((nums[i] + nums[n]) == target)
{
output[0] = n;
output[1] = i;
}
}
}
return output;
}
}
In order to code an O(n) solution, you should loop the elements(numbers) of the array only one time. So, you need to store them in a dictionary. Keys will be numbers, Values will be their indexes. Then will check that is there any key whose value is equal to target - number in the dictionary. Dictionary<TKey, TValue> is a good choice for this problem.
public class Solution {
public int[] TwoSum(int[] nums, int target)
{
//Declare key-value dictionary to store numbers
var set = new Dictionary<int, int>();
//Loop each number in the array until find the complementary number.
for (var i = 0; i < nums.Length; i++)
{
//Assign the element of the array to a integer variable to have an elegant code.
var number = nums[i];
//If the dictionary contains the complementary number then return it.
if (set.ContainsKey(target - number))
{
return new[] {set[target - number], i};
}
//If the current number is not a complementary number then add it to the dictionary.
if (!set.ContainsKey(number))
{
set.Add(number, i);
}
}
//throw the right exception if there is no valid solution.
throw new ArgumentException();
}
}
Assuming that you have good hash function, you can have O(n) complexity. For each p within num you should check if q = k - p exists within num. You can do each each check with O(1) if you use hash based collection (here Dictionary<int, int[]>). The only little problem is p = q = k/2; here we should check if two equal items k/2 are in num.
using System.Linq;
...
public static int[] TwoSum(int[] nums, int k) {
if (nums == null)
throw new ArgumentNullException(nameof(nums));
var dict = nums
.Select((value, index) => new { value = (long)value, index })
.GroupBy(pair => pair.value, pair => pair.index)
.ToDictionary(group => group.Key, group => group.ToArray());
for (int i = 0; i < nums.Length; ++i) {
long p = nums[i];
long q = k - p;
if (dict.TryGetValue(q, out var array))
if (p != q)
return new int[] { i, array[0] };
else if (array.Length >= 2)
return new int[] { array[0], array[1] };
}
return new int[] { -1, -1 };
}
Here I've used long for dictionary key, p and q in order to cope with integer overflow
While everyone debates the fastest algorithm, the following code is quicker than O(n^2) it runs on average O(n log n) and in N space.
using System.Collections.Generic;
public class Solution
{
public int[] TwoSum(int[] nums, int target)
{
int[] output = new int[2];
for (int i = 0; i < nums.Length; i++)
{
for (int n = 1; n < nums.Length; n++)
{
if ((nums[i] + nums[n]) == target)
{
output[0] = n;
output[1] = i;
return output; //early exit giving O(n log n) vs (n^2)
}
}
}
return output; // degenerate case no solution exists
}
}

What's wrong with this simple method to sample from multinomial in C#?

I wanted to implement a simple method to sample from a multinomial distribution in C# (the first argument is an array of integers we want to sample and the second one is the probabilities of selecting each of those integers).
When I do this with numpy in python, the results make sense.
np.random.choice(np.array([1,2,3,4,5,6]),p=np.array([.624,.23,.08,.04, .02, .006]),size=len(b))
I get a lot of 1's (probability 62%), a bunch of 2's, some 3's etc.
However, when I try the implementation below in C# (pretty straightforward inverse transform sampling for multinomial, only relies on a uniform random variable), I get really weird results. For all 1000 samples, I'll often find all 1's. Sometimes, I'll find all 3's (!!??). The results never look like what you would expect (and what you get from the python function - try running it yourself a few times). This is really scary since we rely on these primitives. Does anyone have insight into what might be wrong with the C# version?
static void Main(string[] args)
{
int[] iis = new int[7];
int[] itms = new int[] { 1, 2, 3, 4, 5, 6 };
double[] probs = new double[] { .624, .23, .08, .04, .02, .006 };
for (int i = 0; i < 1000; i++)
{
iis[MultinomialSample(itms, probs)] += 1;
}
foreach (var ii in iis)
{
Console.Write(ii + ",");
}
Console.Read();
}
private static int MultinomialSample(int[] s, double[] ps)
{
double[] cumProbs = new double[ps.Length];
cumProbs[0] = ps[0];
for (int i = 1; i < ps.Length; i++)
{
cumProbs[i] = cumProbs[i - 1] + ps[i];
}
Random random = new Random();
double u = random.NextDouble();
for (int i = 0; i < cumProbs.Length - 1; i++)
{
if (u < cumProbs[i])
{
return s[i];
}
}
return s[s.Length - 1];
}
You're initializing Random each time you call MultinomialSample. If these calls are very close together, Random will be initialized with the same seed (based on the system clock). Try either making Random a private class field: private static Random random = new Random(); or pass it into the method as an argument from Main, where it would be initialized only once:
private static Random random = new Random();
private static int MultinomialSample(IReadOnlyList<int> sample,
IReadOnlyList<double> probabilities)
{
var cumProbs = new double[probabilities.Count];
cumProbs[0] = probabilities[0];
for (var i = 1; i < probabilities.Count; i++)
{
cumProbs[i] = cumProbs[i - 1] + probabilities[i];
}
for (var i = 0; i < cumProbs.Length - 1; i++)
{
if (random.NextDouble() < cumProbs[i])
{
return sample[i];
}
}
return sample[sample.Count - 1];
}
private static void Main()
{
var iis = new int[7];
var items = new[] {1, 2, 3, 4, 5, 6};
var probabilities = new[] {.624, .23, .08, .04, .02, .006};
for (int i = 0; i < 1000; i++)
{
iis[MultinomialSample(items, probabilities)] ++;
}
Console.WriteLine(string.Join(", ", iis));
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
I used Rufus' code in a simulation I was working on and noticed there is still a problem, even after seeding the random number generator just once (which is the correct thing to do). You will notice that as we are iterating, the call to random.NextDouble() generates a new random number each time. This is wrong.
for (var i = 0; i < cumProbs.Length - 1; i++)
{
if (random.NextDouble() < cumProbs[i])
{
return sample[i];
}
}
The random number should be generated outside of the loop, as follows:
var r = random.NextDouble();
for (var i = 0; i < cumProbs.Length - 1; i++)
{
if (r < cumProbs[i])
{
return sample[i];
}
}
You can compare it to the Excel algorithm given on Wikipedia: https://en.wikipedia.org/wiki/Multinomial_distribution. When I made the above change to Rufus' code, I got the desired frequency distribution as specified by the probabilities array.

How to perform combinatoric task in C#

i have a problem with an combinatoric task. I want to have a code which can handle this math calculation 48/5 = 1712304 (5! = 5*4*3*2*1 = 120 48*47*46*45*44 = 205476480 205476480/120 = 1712304)
Here some more details.
I have a string array with 48 strings. The strings have a length between 2 and 3 chars.
string array[] = new string[]{"A1","1D","410" /*[....]*/}
i want to combine 5 strings together, and i want to do this with the whole array, my biggest problem is that a combined string is just allowed to include each of the 48 strings just once. And each combined string have to be unique.
In the end i need a List with 1712304 string entries, which have to be between 10 and 15 degits long. For example one string could look like this "A11A4103E1T".
Back to the math, i know that there are 1712304 combined options so any other result must be wrong. That's where my problem appears.
I created the following code without succesful result
string[] siDigit = new string[iNumDigits];
List<string> liste = new List<string>();
const int iDigitBase = 48;
const int iNumDigits = 5;
for (int i = 0; i < 1712303; ++i)
{
int i2 = i;
for (int i3 = 0; i3 < iNumDigits; ++i3)
{
siDigit[i3] = array[i2 % iDigitBase];
i2 /= iDigitBase;
}
bool duplicate_free = siDigit.Distinct().Count() == siDigit.Length;
if (duplicate_free == true)
{
liste.Add(siDigit[0] + siDigit[1] + siDigit[2] + siDigit[3] + siDigit[4]);
Console.Write(siDigit[0] + siDigit[1] + siDigit[2] + siDigit[3] + siDigit[4]);
Console.WriteLine();
}
}
What i get is way to less entries in my list, i just get 1317051 entries and dont know why. I cant find any solution for my problem, may someone out there can help me out.
Any help would be greatly appreciated.
P.S In germany they dont teach better english :)
I think your algorithm is wrong.
Consider i equals 0, i2 equals 0, so siDigit[i3](i3 = 0, 1, 2, 3 ,4) are array[0], duplicate_free is false. You lose one. So, you can not get all entries.
Here is a recursive algorithm:
private static void GetCombination(ref List<string[]> list, string[] t, int n, int m, int[] b, int M)
{
for (int i = n; i >= m; i--)
{
b[m - 1] = i - 1;
if (m > 1)
{
GetCombination(ref list, t, i - 1, m - 1, b, M);
}
else
{
if (list == null)
{
list = new List<string[]>();
}
string[] temp = new string[M];
for (int j = 0; j < b.Length; j++)
{
temp[j] = t[b[j]];
}
list.Add(temp);
}
}
}
public static List<string[]> GetCombination(string[] t, int n)
{
if (t.Length < n)
{
return null;
}
int[] temp = new int[n];
List<string[]> list = new List<string[]>();
GetCombination(ref list, t, t.Length, n, temp, n);
return list;
}

Most efficient way to randomly "sort" (Shuffle) a list of integers in C#

I need to randomly 'sort' a list of integers (0-1999) in the most efficient way possible. Any ideas?
Currently, I am doing something like this:
bool[] bIndexSet = new bool[iItemCount];
for (int iCurIndex = 0; iCurIndex < iItemCount; iCurIndex++)
{
int iSwapIndex = random.Next(iItemCount);
if (!bIndexSet[iSwapIndex] && iSwapIndex != iCurIndex)
{
int iTemp = values[iSwapIndex];
values[iSwapIndex] = values[iCurIndex];
values[iCurIndex] = values[iSwapIndex];
bIndexSet[iCurIndex] = true;
bIndexSet[iSwapIndex] = true;
}
}
A good linear-time shuffling algorithm is the Fisher-Yates shuffle.
One problem you'll find with your proposed algorithm is that as you near the end of the shuffle, your loop will spend a lot of time looking for randomly chosen elements that have not yet been swapped. This may take an indeterminate amount of time once it gets to the last element to swap.
Also, it looks like your algorithm will never terminate if there are an odd number of elements to sort.
static Random random = new Random();
public static IEnumerable<T> RandomPermutation<T>(IEnumerable<T> sequence)
{
T[] retArray = sequence.ToArray();
for (int i = 0; i < retArray.Length - 1; i += 1)
{
int swapIndex = random.Next(i, retArray.Length);
if (swapIndex != i) {
T temp = retArray[i];
retArray[i] = retArray[swapIndex];
retArray[swapIndex] = temp;
}
}
return retArray;
}
modified to handle lists or other objects implementing IEnumerable
We can make an extension method out of this to get a Random enumerator for any IList collection
class Program
{
static void Main(string[] args)
{
IList<int> l = new List<int>();
l.Add(7);
l.Add(11);
l.Add(13);
l.Add(17);
foreach (var i in l.AsRandom())
Console.WriteLine(i);
Console.ReadLine();
}
}
public static class MyExtensions
{
public static IEnumerable<T> AsRandom<T>(this IList<T> list)
{
int[] indexes = Enumerable.Range(0, list.Count).ToArray();
Random generator = new Random();
for (int i = 0; i < list.Count; ++i )
{
int position = generator.Next(i, list.Count);
yield return list[indexes[position]];
indexes[position] = indexes[i];
}
}
}
This uses a reverse Fisher-Yates shuffle on the indexes of the list we want to randomly enumerate through. Its a bit of a size hog (allocating 4*list.Count bytes), but runs in O(n).
As Greg pointed out the Fisher-Yates shuffle would be the best approach. Here is an implementation of the algorithm from Wikipedia:
public static void shuffle (int[] array)
{
Random rng = new Random(); // i.e., java.util.Random.
int n = array.length; // The number of items left to shuffle (loop invariant).
while (n > 1)
{
int k = rng.nextInt(n); // 0 <= k < n.
n--; // n is now the last pertinent index;
int temp = array[n]; // swap array[n] with array[k] (does nothing if k == n).
array[n] = array[k];
array[k] = temp;
}
}
The implementation above relies on
Random.nextInt(int) providing
sufficiently random and unbiased
results
I am not sure of the efficiency factor, but I have used something similar to the following, if you aren't opposed to using an ArrayList:
private ArrayList ShuffleArrayList(ArrayList source)
{
ArrayList sortedList = new ArrayList();
Random generator = new Random();
while (source.Count > 0)
{
int position = generator.Next(source.Count);
sortedList.Add(source[position]);
source.RemoveAt(position);
}
return sortedList;
}
Using this, you do not have to worry about the intermediate swapping.
To improve your efficiency you can keep a set of values/indices that have been swapped rather than a boolean for indicating they were swapped. Pick your randomized swap index from the remaining pool. When the pool is 0, or when you made it through the initial list then you are done. You don't have the potential to try to select a random swap index value.
When you do a swap, just remove them from the pool.
For the size of data you are looking at it is no big deal.
itemList.OrderBy(x=>Guid.NewGuid()).Take(amount).ToList()
ICR's answer is very fast, but the resulting arrays aren't distributed normally. If you want a normal distribution, here's the code:
public static IEnumerable<T> RandomPermutation<T>(this IEnumerable<T> sequence, int start,int end)
{
T[] array = sequence as T[] ?? sequence.ToArray();
var result = new T[array.Length];
for (int i = 0; i < start; i++)
{
result[i] = array[i];
}
for (int i = end; i < array.Length; i++)
{
result[i] = array[i];
}
var sortArray=new List<KeyValuePair<double,T>>(array.Length-start-(array.Length-end));
lock (random)
{
for (int i = start; i < end; i++)
{
sortArray.Add(new KeyValuePair<double, T>(random.NextDouble(), array[i]));
}
}
sortArray.Sort((i,j)=>i.Key.CompareTo(j.Key));
for (int i = start; i < end; i++)
{
result[i] = sortArray[i - start].Value;
}
return result;
}
Note that in my tests, this algorithm was 6 times slower than the one ICR provided, however this is the only way I could come up with to get a normal result distribution
Wouldn't something like this work?
var list = new[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
var random = new Random();
list.Sort((a,b)=>random.Next(-1,1));
what about :
System.Array.Sort(arrayinstance, RandomizerMethod);
...
//any evoluated random class could do it !
private static readonly System.Random Randomizer = new System.Random();
private static int RandomizerMethod<T>(T x, T y)
where T : IComparable<T>
{
if (x.CompareTo(y) == 0)
return 0;
return Randomizer.Next().CompareTo(Randomizer.Next());
}
voila!
Here is what I used.
This is surely not the fastest one, but it is probably good enough for most cases and most importantly, it is very simple.
IEnumerable<ListItem> list = ...;
Random random = new Random(); // important to not initialize a new random in the OrderBy() function
return list.OrderBy(i => random.Next());
You can use a NuGet package called ListShuffle (source code) to shuffle a list in a thread-safe way using the Fisher-Yates algorithm, with optional cryptographically-strong random.
var myList = new List<string>();
myList.Add("Item A");
myList.Add("Item B");
myList.Add("Item C");
myList.Shuffle();
or (less performant but cryptographically-strong)
var myList = new List<string>();
myList.Add("Item A");
myList.Add("Item B");
myList.Add("Item C");
myList.CryptoStrongShuffle();
I made a method using a temporary Hashtable, allowing the Hashtable's natural key sort to randomize. Simply add, read and discard.
int min = 1;
int max = 100;
Random random;
Hashtable hash = new Hashtable();
for (int x = min; x <= max; x++)
{
random = new Random(DateTime.Now.Millisecond + x);
hash.Add(random.Next(Int32.MinValue, Int32.MaxValue), x);
}
foreach (int key in hash.Keys)
{
HttpContext.Current.Response.Write("<br/>" + hash[key] + "::" + key);
}
hash.Clear(); // cleanup

Categories

Resources