I have a multidimensional array with five countries and some medals. The last column is the total and i need to return the country with most medals. My code is "working" as long as there are no two countries with the same number of medals and those being the max number.
Problably i just don't have enough experience with arrays, but how can i return more than one contry, if i need?
string [,] medals = new string[5, 5];
Random rdn = new Random();
medals[0, 0] = "Brazil";
medals[1, 0] = "USA";
medals[2, 0] = "Russia";
medals[3, 0] = "France";
medals[4, 0] = "Egypt";
for (int i = 0; i < medals.GetLength(0); i++)
for (int j = 1; j < medals.GetLength(1); j++)
{
//This fills the gold, silver and copper medals
if (j < medals.GetLength(1)-1)
medals[i, j] = rdn.Next(1, 6).ToString();
else
//This fills the total medals
medals[i, j] = (int.Parse(medals[i, 1]) + int.Parse(medals[i,2]) + int.Parse(medals[i,3])).ToString();
}
//The first index stores the max number so far and the second stores the name of the country
string [] winner = { "0", "0" };
for (int i = 0; i < medals.GetLength(0); i++)
{
if (int.Parse(medals[i,4]) > int.Parse(winner[0]))
{
winner[0] = medals[i, 4];
winner[1] = medals[i, 0];
}
}
You could use a list to store the winners.
var listWinners = new List<KeyValuePair<string,string>>();
for (int i = 0; i < medals.GetLength(0); i++)
{
if ((listWinners.Count() == 0)||(int.Parse(medals[i,4]) > int.Parse(listWinners.First().Value)))
{
listWinners.Clear();
listWinners.Add(new KeyValuePair<string,string>(medals[i,0],medals[i,4]));
}
else if (int.Parse(medals[i,4]) == int.Parse(listWinners.First().Value))
{
listWinners.Add(new KeyValuePair<string,string>(medals[i,0],medals[i,4]));
}
}
But I would like reiterate what has been said in the comments, it would be much better if you could use a List of Object rather than multi-dimentional array. It would increase your readability of code and make things much simpler.
A dictionary would be a much easier starting place. You could then just sort based on the values in the dict and use a simple loop to check for duplicate values.
There are a lot of things I would do differently than you, but that's besides the point (see note at the end). Your issue is how to deal with the situation where you have multiple countries with equal and max number of medals.
How to return multiple countries?
Well, that's easy: imagine you return the winner from the below function:
string[] GetWinner() {
// your code
return new[] { "20", "USA" };
}
Then there is no change in the data type, simply add another country to the array and the calling code should check how many you have
string[] GetWinner() {
// your code
return new[] { "20", "USA", "CAN" };
}
Now if you have a problem as to how to create an array whose size is unknown while creating it, then the usual solution is to use List<>, which in this case will act as a re-sizable array for you.
The final code would look something like below
static string[] GetWinner(string[,] medals) {
int rows = medals.GetLength(0);
var winners = new List<string>();
int maxMedals = 0;
for (var i = 0; i < rows; i++) {
var n = int.Parse(medals[i, 4]);
maxMedals = n > maxMedals ? n : maxMedals;
}
for (var i = 0; i < rows; i++) {
var n = int.Parse(medals[i, 4]);
if (n == maxMedals)
winners.Add(medals[i, 0]);
}
winners.Insert(0, maxMedals.ToString());
return winners.ToArray();
}
Now, I would advise you to use a better data structure to store your medals. But since I don't know the full situation, I would guess, something like below is reasonable. Instead of using named types, you can use ValueTuple - to make the code concise, if the code related to these objects are restricted to a small area of a the code file. This should avoid allocating big chunk of memory associated with 2D arrays, and also storing of int in string.
public class CountryMedalTally {
public string Country { get; set; }
public string[] Medals { get; set; }
public int MedalCount { get; set; }
}
public class Winner {
public List<string> Country { get; set; }
public int MedalCount { get; set; }
}
List<CountryMedalTally> AllMedals;
Related
I am trying to serialize a 2D array of strings to send over a network.
I have a couple ideas but I seem to be blocked by api or efficiency. I really don't want to serialize and send a small 2D array across a network 10 times a second when I only need it when I collide with something and ask for the information.
I have a list of items a player has in his cart. I want to make it okay to steal from that cart, so the other player has to be able to see what's in the cart.
If I use onphotonserializeview I thought I could convert the flatten the 2d array of strings into a 1D array of strings with a delimiter and stream.sendnext the delimited line and reconstitute on the other side, or some variation of that functionality.
public void serialize_merchandise_list() {
int width = 0;
int length = 0;
while((width < cart_list_width) && (length < cart_list_width)) {
width++;
if (width >= cart_list_width) {
length++;
width = 0;
}
// convert to bytes and then to string and append
System.Text.ASCIIEncoding.ASCII.GetBytes(merchandise_items[width, length]));
}
}
But doing that unnecessarily is an operation time nightmare, I want it on demand.
I was going to do a punrpc but I can't get a return value or ref parameter. What is the best approach here?
I want:
collide with cart
do you want to steal from cart --> yes --> show list
else --> go on your way
Afaik a one-dimensional array of strings would be no problem for Photon.
So I guess you could just flatten the array and additionally send the second size - lets name it element size (in contrary to the first one - the element count) as parameters.
Like e.g. lets say your array looks like
string[,] array2D = new string[4,2]{{"a", "b"}, {"c","d"}, {"e","f"}, {"g","h"}};
Then you would know the second (elementSize) dimension using either hardcoded or GetLength(int)
var elementSize = array2D.GetLength(1);
and you would simply flatten the array using
string[] arrayFlat = array2D.Cast<string>().ToArray();
So you would send these two informations via photon (I don't know photon in detail) but afaik you can do this one time without having to send it continiously. The two parameters would be
int elementSize, string[] arrayFlat
in this case with the values
2, string[8]{"a","b","c","d","e","f","g","h"}
So together:
public void SendArray2D()
{
int elementSize = array2D.GetLength(1);
string[] arrayFlat = array2D.Cast<string>().ToArray();
photonView.RPC(nameof(ReceiveArray2D), RpcTarget.All, elementSize, (object) arrayFlat);
}
Then on the receiver part you are getting
int elementSize = 2, string[] arrayFlat = string[8]{"a","b","c","d","e","f","g","h"}
and have to convert it back. You already know the second dimension elementSize = 2 so in order to get also the first one you simply do
var elementCount = arrayFlat.Length / elementSize; // = 4
so you know the 2D array you will have to fill would be
string[,] array2D = new string[elementCount, elementSize]; // = 4,2
and then you can simply iterate it and do something like
for (var x = 0; x < elementCount; x++)
{
for (int y = 0; y < elementSize; y++)
{
array2D[x, y] = arrayFlat[x * elementSize + y];
}
}
So together
[PunRpc]
public void ReceiveArray2D(int elementSize, string[] arrayFlat)
{
var elementCount = arrayFlat.Length / elementSize;
array2D = new string[elementCount, elementSize];
for (var x = 0; x < elementCount; x++)
{
for (int y = 0; y < elementSize; y++)
{
array2D[x, y] = arrayFlat[x * elementSize + y];
}
}
// Could also e.g. call some event like
OnReceivedArray2D?.Invoke (array2D);
}
public event Action<string[,]> OnReceivedArray2D;
So you could attach listeners to the event via
reference.OnReceivedArray2D += SomeHandler;
private void SomeHandler(string [,])
{
// ...
}
Or alternatively you could implement a class that stores your data in a flat array but lets you access it like if it would be a 2D array (in general a 2D array is anyway stored in memory as a flat one)
[Serializable]
public class SerializableArray2D
{
public readonly string[] ArrayFlat;
public readonly ElementSize;
public SerializableArray2D(int elementSize, string[] arrayFlat)
{
ElementSize = elementSize;
ArrayFlat = arrayFlat;
}
public SerializableArray2D(string[,] array2D) : this(array2D.GetLength(1), array2D.Cast<string>().ToArray()) { }
public SerializableArray2D(int elementSize, int elementCount) : this(elementSize, new string[elementCount]){}
public string this[int x, int y]
{
get { return ArrayFlat[x * ElementSize + y]; }
set { ArrayFlat[x * ElementSize + y] = value; }
}
}
usage would be e.g. Initialize it
var array2D = new string[4,2]{{"a", "b"}, {"c","d"}, {"e","f"}, {"g","h"}};
var serializableArray2D = new SerializableArray2D(array2D);
For accessing specific indices like in a 2D array
string example = serializableArray2D[1,1];
serializableArray2D[3,0] = "example";
For sending it
photonView.RPC(nameof(Receive), RpcTarget.All, serializableArray2D.ElementSize, (object)serializableArray2D.ArrayFlat);
And when receiving it
[PunRPC]
public void Receive(int elementSize, string[] arrayFlat)
{
serializableArray2D = new SerializableArray2D(elementSize, arrayFlat);
// Again e.g. call an event
OnReceivedSerializableArray2D?.Invoke(serializableArray2D);
}
public event Action<SerializableArray2D> OnReceivedSerializableArray2D;
Hello I have an array of enumerations, and I'm trying sort that array by their enumeration value and get the array index's of the top
private enum Values
{
LOW,
MEDIUM,
HIGH
}
private Values[] Settings = new Values[10];
Settings[0] = LOW;
Settings[1] = HIGH;
Settings[2] = MEDIUM;
Settings[3] = LOW;
Settings[4] = LOW;
Settings[5] = LOW;
Settings[6] = LOW;
Settings[7] = LOW;
Settings[8] = MEDIUM;
Settings[9] = MEDIUM;
Basically now, with what I have above, I need to sort the settings array by enumeration value and get the array indexes of the top (let's say 3) items;
So I'd get back values 1, 2, 8
The platform I'm using does not support LINQ so those handy functions are not available.
I've been trying to wrap my head around this but it would help to have another pair of eyes.
thanks.
Implement a wrapper reference type,
class ValueWrapper : IComparable<ValueWrapper>
{
public Values Value { get; set; }
public int Index { get; set; }
public int CompareTo(ValueWrapper other)
{
return this.Value.CompareTo(other.Value) * -1; // Negating since you want reversed order
}
}
Usage -
ValueWrapper[] WrappedSettings = new ValueWrapper[10];
for(int i = 0; i < WrappedSettings.Length; i++)
{
WrappedSettings[i] = new ValueWrapper { Value = Settings[i], Index = i };
}
Array.Sort(WrappedSettings);
WrappedSettings will be sorted as you specified, preserving the indexes they were in the original array.
how about this:
Values first = Values.Low,second = Values.Low,third = Values.Low;
int firstI = -1,secondI = -1, thirdI = -1;
for(int i = 0;i < Settings.Length;i++)
{
if(Settings[i] > first || firstI == -1)
{
third = second;
thirdI = secondI;
second= first;
secondI= firstI;
first = Settings[i];
firstI = i;
}
else if(Settings[i] > second || secondI == -1)
{
third = second;
thirdI = secondI;
second = Settings[i];
secondI = i;
}
else if(Settings[i] > third || thirdI == -1)
{
third = Settings[i];
thirdI = i;
}
}
So, since you say you work in an environment where Linq is not available, I assume that other things like generics, nullables and so on will not be available either. A very low-tech solution.
Basic idea:
For every possible enum value, from highest to lowest, go through the list. If we find that value, output it and remember how many we have output. If we reach 3, stop the algorithm.
So, we first look for HIGH in the list, then for MEDIUM and so on.
class Program
{
private enum Values
{
LOW,
MEDIUM,
HIGH
}
static void Main(string[] args)
{
// Sample data
Values[] settings = new Values[10];
settings[0] = Values.LOW;
settings[1] = Values.HIGH;
settings[2] = Values.MEDIUM;
settings[3] = Values.LOW;
settings[4] = Values.LOW;
settings[5] = Values.LOW;
settings[6] = Values.LOW;
settings[7] = Values.LOW;
settings[8] = Values.MEDIUM;
settings[9] = Values.MEDIUM;
// Get Values of the enum type
// This list is sorted ascending by value but may contain duplicates
Array enumValues = Enum.GetValues(typeof(Values));
// Number of results found so far
int numberFound = 0;
// The enum value we used during the last outer loop, so
// we skip duplicate enum values
int lastValue = -1;
// For each enum value starting with the highest to the lowest
for (int i= enumValues.Length -1; i >= 0; i--)
{
// Get this enum value
int enumValue = (int)enumValues.GetValue(i);
// Check whether we had the same value in the previous loop
// If yes, skip it.
if(enumValue == lastValue)
{
continue;
}
lastValue = enumValue;
// For each entry in the list where we are searching
for(int j=0; j< settings.Length; j++)
{
// Check to see whether it is the currently searched value
if (enumValue == (int)settings[j])
{
// if yes, then output it.
Console.WriteLine(j);
numberFound++;
// Stop after 3 found entries
if (numberFound == 3)
{
goto finished;
}
}
}
}
finished:
Console.ReadLine();
}
}
Output is as requested 1,2,8
I'm not sure if this is exactly what you want because it doesn't sort the original array, but one way to get the indexes of the top three values is to simply store the indexes of the top values in another array. Then we can loop through the original array, and for each item, see if it's larger than any of the items at the indexes we've stored so far. If it is, then swap it with that item.
For example:
// Start the topIndexes array with all invalid indexes
var topIndexes = new[] {-1, -1, -1};
for (var settingIndex = 0; settingIndex < Settings.Length; settingIndex++)
{
var setting = Settings[settingIndex];
var topIndexLessThanSetting = -1;
// Find the smallest topIndex setting that's less than this setting
for (int topIndex = 0; topIndex < topIndexes.Length; topIndex++)
{
if (topIndexes[topIndex] == -1)
{
topIndexLessThanSetting = topIndex;
break;
}
if (setting <= Settings[topIndexes[topIndex]]) continue;
if (topIndexLessThanSetting == -1 ||
Settings[topIndexes[topIndex]] < Settings[topIndexes[topIndexLessThanSetting]])
{
topIndexLessThanSetting = topIndex;
}
}
topIndexes[topIndexLessThanSetting] = settingIndex;
}
// topIndexes = { 1, 2, 8 }
I am looking for optimization for the following.
I have an object that has a few properties. For simplicity i will show the only 2 that matter in this scenario.
public class DomainData
{
public long Id{ get; set; }
public long SoldTickets { get; set; }
}
I make a call to my db and get a list of the above object:
var databaseData = _iOvervatchManager.GetDomainData(id);// gets date from db
var model = new List<DomainModel>();
Now I need to calculate how many tickets have been sold between list items.
current = current - previous
I do the calculation with the following code:
for (int i = 0; i <= databaseData.Count() -1; i++)
{
if (i != 0)
{
long ticket = databaseData[i].SoldTickets- databaseData[i - 1].SoldTickets;
model.Add(new DomainModel
{
DomainId = databaseData[i].DomainId ,
SoldTicketsLastUpdate = ticket
});
}
}
And now set the value on the original object.
for(int i= 0; i< databaseData.Count(); i++)
{
if(databaseData[i].Id == model[i].DomainId )
databaseData[i].SoldTickets = model[i].SoldTicketsLastUpdate;
}
I consider this an awful way of accomplishing this since I recon I can do this in the first loop but I can't figure out how.
my first attempt was :
for (int i = 0; i <= databaseData.Count() -1; i++)
{
if (i != 0)
{
databaseData[i].SoldTickets
= databaseData[i].SoldTickets - databaseData[i - 1].SoldTickets;
}
}
But this was wrong since i change the object value and when I come to the next increment the previous value has been modified so the current for that loop increment gets a wrong calculation.
How can I optimize this?
Assuming that no new data will be added after this runs (!!), execute the for-loop backwards:
for (int i = databaseData.Count() - 1; i > 0; i--)
{
databaseData[i].SoldTickets = databaseData[i].SoldTickets - databaseData[i - 1].SoldTickets;
}
And because the loop only runs for i > 0, the check for i != 0 is unneeded.
Say I have four teams, ABCD, I want to create matches so that the teams evenly have to do them:
not desired
A vs B
A vs C
A vs D
B vs C
B vs D
C vs D
desired
A vs B
C vs D
B vs C
A vs D
A vs C
B vs D
Another way of putting it: I want the teams to have a match as few in a row as possible.
Target language is C#, but I can translate easily.
Edit: Quick sidenote, it can be more than 4 teams!
One way to solve this is by the following steps:
Create a collection containing the total number of match combinations.
Create a new collection with the same length as the collection in step 1.
Go through the items in step 1, add the same item in step 2, with the condition that the next item to be added should have the maximum difference between it and the last added item.
Some sample code:
// Just a container to conveniently hold a match between two teams
public class Match
{
public Match(string teamOne, string teamTwo)
{
TeamOne = teamOne;
TeamTwo = teamTwo;
}
public string TeamOne { get; private set; }
public string TeamTwo { get; private set; }
public override string ToString()
{
return String.Format("{0} vs {1}", TeamOne, TeamTwo);
}
}
public class MatchMaking
{
public MatchMaking()
{
Teams = new List<string> { "A", "B", "C", "D", "E" };
}
public IList<string> Teams { get; private set; }
public IList<Match> GetMatches()
{
var unorderedMatches = GetUnorderedMatches();
// The list that we will eventually return
var orderedMatches = new List<Match>();
// Track the most recently added match
Match lastAdded = null;
// Loop through the unordered matches
// Add items to the ordered matches
// Add the one that is most different from the last added match
for (var i = 0; i < unorderedMatches.Count; i++)
{
if (lastAdded == null)
{
lastAdded = unorderedMatches[i];
orderedMatches.Add(unorderedMatches[i]);
unorderedMatches[i] = null;
continue;
}
var remainingMatches = unorderedMatches.Where(m => m != null);
// Get the match which is the most different from the last added match
// We do this by examining all of the unadded matches and getting the maximum difference
Match mostDifferentFromLastAdded = null;
int greatestDifference = 0;
foreach (var match in remainingMatches)
{
var difference = GetDifference(lastAdded, match);
if (difference > greatestDifference)
{
greatestDifference = difference;
mostDifferentFromLastAdded = match;
}
if (difference == 2)
{
break;
}
}
// Add the most different match
var index = unorderedMatches.ToList().IndexOf(mostDifferentFromLastAdded);
lastAdded = unorderedMatches[index];
orderedMatches.Add(unorderedMatches[index]);
unorderedMatches[index] = null;
}
return orderedMatches;
}
// Create a list containing the total match combinations with an arbitrary order
private List<Match> GetUnorderedMatches()
{
var totalNumberOfCombinations = AdditionFactorial(Teams.Count - 1);
var unorderedMatches = new List<Match>(totalNumberOfCombinations);
for (int i = 0; i < Teams.Count; i++)
{
for (int j = 0; j < Teams.Count; j++)
{
if (j <= i) continue;
unorderedMatches.Add(new Match(Teams[i], Teams[j]));
}
}
return unorderedMatches;
}
// Get the difference between two matches
// 0 - no difference, 1 - only one team different, 2 - both teams different
private int GetDifference(Match matchOne, Match matchTwo)
{
var matchOneTeams = new HashSet<string> { matchOne.TeamOne, matchOne.TeamTwo };
var matchTwoTeams = new HashSet<string> { matchTwo.TeamOne, matchTwo.TeamTwo };
var intersection = matchOneTeams.Intersect(matchTwoTeams);
return (intersection.Count() - 2) * -1;
}
// Just a helper to get the total number of match combinations
private int AdditionFactorial(int seed)
{
int result = 0;
for (int i = seed; i > 0; i--)
{
result += i;
}
return result;
}
}
public class Program
{
private static void Main(string[] args)
{
var matchMaking = new MatchMaking();
foreach (var match in matchMaking.GetMatches())
{
Console.WriteLine(match);
}
}
}
I think you may achieve what you need doing as follows. If you've got n number of teams, all the possible matches between teams can be represented with a Kn Complete graph.
The way I would come up with your desired sorting, is taking (removing) edges from that graph, one at a time, always trying to find an edge that matches teams that didn't match immediately before. Further more, I think this approach (with a little variation) can be used to generate the best way to maximize concurrent matches, if each time you take an edge you pick the one with the teams that haven't played in most time.
For simplicity, lets assume that teams are ints in the range of 0 to n-1. The graph can simply be represented with a boolean matrix. To pick the match with the teams that haven't played in most time, you can keep track of the last time each team played. For n teams, you'll have a total of n*(n-1)/2 number of matches.
IEnumerable<Tuple<int,int>> GenerateMatches(int n) {
bool[,] pendingMatches = new bool[n,n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++)
pendingMatches[i,j] = true;
}
int[] lastPlayed = new int[n];
int totalMatches = n*(n-1)/2;
for (int m = 1; m <= totalMatches; m++) {
Tuple<int, int> t = null;
int longestPlayed = -1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (pendingMatches[i,j]) {
int moreRecentlyPlayed = Math.Max(lastPlayed[i], lastPlayed[j]);
int timeSinceLastPlay = m - moreRecentlyPlayed;
if (timeSinceLastPlay > longestPlayed) {
longestPlayed = timeSinceLastPlay;
t = Tuple.Create(i,j);
}
}
}
}
lastPlayed[t.Item1] = lastPlayed[t.Item2] = m;
pendingMatches[t.Item1, t.Item2] = false;
yield return t;
}
}
The part that chooses the next match are the two most nested fors. The complexity of that part can be improved if you use some kind of priority queue adapted to adjust the priority of edges that involve the teams of the last picked edge after updating the lastPlayed array.
Hope that helps.
How can I change my C# code below to list all possible permutations without repetitions? For example: The result of 2 dice rolls would produce 1,1,2 so that means 2,1,1 should not appear.
Below is my code:
string[] Permutate(int input)
{
string[] dice;
int numberOfDice = input;
const int diceFace = 6;
dice = new string[(int)Math.Pow(diceFace, numberOfDice)];
int indexNumber = (int)Math.Pow(diceFace, numberOfDice);
int range = (int)Math.Pow(diceFace, numberOfDice) / 6;
int diceNumber = 1;
int counter = 0;
for (int i = 1; i <= indexNumber; i++)
{
if (range != 0)
{
dice[i - 1] += diceNumber + " ";
counter++;
if (counter == range)
{
counter = 0;
diceNumber++;
}
if (i == indexNumber)
{
range /= 6;
i = 0;
}
if (diceNumber == 7)
{
diceNumber = 1;
}
}
Thread.Sleep(1);
}
return dice;
}
The simplest possible way I could think of:
List<string> dices = new List<string>();
for (int i = 1; i <= 6; i++)
{
for (int j = i; j <= 6; j++)
{
for (int k = j; k <= 6; k++)
{
dices.Add(string.Format("{0} {1} {2}", i, j, k));
}
}
}
I have written a class to handle common functions for working with the binomial coefficient, which is the type of problem that your problem falls under. It performs the following tasks:
Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters. This method makes solving this type of problem quite trivial.
Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle. My paper talks about this. I believe I am the first to discover and publish this technique, but I could be wrong.
Converts the index in a sorted binomial coefficient table to the corresponding K-indexes.
Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.
The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to perform the 4 above methods. Accessor methods are provided to access the table.
There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.
To read about this class and download the code, see Tablizing The Binomial Coeffieicent.
I'm bad at math as well, this may or may not be helpful...
Program.cs
namespace Permutation
{
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Generating list.");
var dice = new List<ThreeDice>();
for (int x = 1; x <= 6; x++)
{
for (int y = 1; y <= 6; y++)
{
for (int z = 1; z <= 6; z++)
{
var die = new ThreeDice(x, y, z);
if (dice.Contains(die))
{
Console.WriteLine(die + " already exists.");
}
else
{
dice.Add(die);
}
}
}
}
Console.WriteLine(dice.Count + " permutations generated.");
foreach (var die in dice)
{
Console.WriteLine(die);
}
Console.ReadKey();
}
}
}
ThreeDice.cs
namespace Permutation
{
using System;
using System.Collections.Generic;
public class ThreeDice : IEquatable<ThreeDice>
{
public ThreeDice(int dice1, int dice2, int dice3)
{
this.Dice = new int[3];
this.Dice[0] = dice1;
this.Dice[1] = dice2;
this.Dice[2] = dice3;
}
public int[] Dice { get; private set; }
// IEquatable implements this method. List.Contains() will use this method to see if there's a match.
public bool Equals(ThreeDice other)
{
// Get the current dice values into a list.
var currentDice = new List<int>(this.Dice);
// Check to see if the same values exist by removing them one by one.
foreach (int die in other.Dice)
{
currentDice.Remove(die);
}
// If the list is empty, we have a match.
return currentDice.Count == 0;
}
public override string ToString()
{
return "<" + this.Dice[0] + "," + this.Dice[1] + "," + this.Dice[2] + ">";
}
}
}
Good luck.
The important part of the question is that you want distinct sets (regardless of order). So for example, a dice roll of [1, 2, 1] is equal to a dice roll of [1, 1, 2].
I'm sure there are a number of ways to skin this cat, but the first thought that comes to mind is to create a EqualityComparer which will compare the list of dice in the way you want, and then use LINQ with the Distinct() method.
Here is the EqualityComparer, which takes 2 List<int> and says they are equal if the elements are all equal (regardless of order):
private class ListComparer : EqualityComparer<List<int>>
{
public override bool Equals(List<int> x, List<int> y)
{
if (x.Count != y.Count)
return false;
x.Sort();
y.Sort();
for (int i = 0; i < x.Count; i++)
{
if (x[i] != y[i])
return false;
}
return true;
}
public override int GetHashCode(List<int> list)
{
int hc = 0;
foreach (var i in list)
hc ^= i;
return hc;
}
}
And here is the code that uses it. I'm using LINQ to build up the list of all combinations... you could also do this with nested for loops but I like this better for some reason:
public static void Main()
{
var values = new[] { 1,2,3,4,5,6 };
var allCombos = from x in values
from y in values
from z in values
select new List<int>{ x, y, z };
var distinctCombos = allCombos.Distinct(new ListComparer());
Console.WriteLine("#All combos: {0}", allCombos.Count());
Console.WriteLine("#Distinct combos: {0}", distinctCombos.Count());
foreach (var combo in distinctCombos)
Console.WriteLine("{0},{1},{2}", combo[0], combo[1], combo[2]);
}
Hope that helps!
Here is generic c# version using recursion (basically the recursive method takes number of dices or number of times the dice has been tossed) and returns all the combinations strings ( for ex, for '3' as per the question - there will be 56 such combinations).
public string[] GetDiceCombinations(int noOfDicesOrnoOfTossesOfDice)
{
noOfDicesOrnoOfTossesOfDice.Throw("noOfDicesOrnoOfTossesOfDice",
n => n <= 0);
List<string> values = new List<string>();
this.GetDiceCombinations_Recursive(noOfDicesOrnoOfTossesOfDice, 1, "",
values);
return values.ToArray();
}
private void GetDiceCombinations_Recursive(int size, int index, string currentValue,
List<string> values)
{
if (currentValue.Length == size)
{
values.Add(currentValue);
return;
}
for (int i = index; i <= 6; i++)
{
this.GetDiceCombinations_Recursive(size, i, currentValue + i, values);
}
}
Below are corresponding tests...
[TestMethod]
public void Dice_Tests()
{
int[] cOut = new int[] { 6, 21, 56, 126 };
for(int i = 1; i<=4; i++)
{
var c = this.GetDiceCombinations(i);
Assert.AreEqual(cOut[i - 1], c.Length);
}
}