Related
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 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;
I want to write a code that every 25 times, the program should go back to run Part_1_code as follow. Here is problem that, Part_2_code has a lot of variables created in the Part_1_code, so following code is not allowed, but we couldn't not declare those variables at the beginning, since they are all anonymous type (read-only) so how to solve it? I do not wish to create a new class.
int Count = 1;
foreach (DateTime Date in TestDate)
{
if(Count == 1 || Count == 25){
Part_1_code;
Count = 1;
}
Pair_2_code;
Count++;
}
Variables which need to be accessible in a certain scope must also be defined in that scope, or a parent (outer) scope. Apart from that, it might be simpler to use a plain for loop in this case, combined with a module (%) operator.
It would also be slightly more precise to say you execute your "specific" code every 24 times, the way it's written. Using 1-based indexing in C-like languages is rather awkward.
for (var count = 0; count < TestDates.Count; count++)
{
var date = TestDates[count];
SomeStuff stuff = null;
if (count % 24 == 0)
{
// runs on 0, 24, 48, ...
stuff = new SomeStuff();
}
// runs on each iteration, 'stuff' will be non-null only if
// previous part was executed.
}
You can also extract these branches into methods, and pass the shared state as a parameter:
// decide whether this should be outside the loop
// (i.e. keep the state from previous iterations),
// or declared within the `for` loop
var state = new SharedState();
for (var count = 0; count < TestDates.Count; count++)
{
var date = TestDates[count];
if (count % 24 == 0)
{
// runs on 0, 24, 48, ...
ProcessPart1(state);
}
// runs on each iteration
ProcessPart2(state);
}
Where SharedState contains any data you need to share between these branches:
class SharedState
{
public int SomeValue { get; set; }
public string SomeOtherValue { get; set; }
}
If your ProcessPart1 method returns a value, you can even use a ternary operator to simplify the code:
for (var count = 0; count < TestDates.Count; count++)
{
var date = TestDates[count];
// runs on 0, 24, 48, ...
var someData = (count % 24 == 0) ? Process1(date) : null;
// runs on each iteration
Process2(someData);
}
One option is to make state a private field in the parent class, but a common rule of thumb is to try to limit scope of your variables as much as possible.
Of course, if you posted some actual code which executes in these two branches, it could perhaps be possible to refactor the code slightly better.
This seems pretty straightforward, Part_1_Code can just be a function which returns your data.
int Count = 1;
Part1Result p1 = null;
foreach (DateTime Date in TestDate)
{
if(Count == 1 or Count == 25){
p1 = Part_1_code();
Count = 1;
}
//Part_2_code
//use variable p1 here - its the results from Part1Code
Count++;
}
elsewhere
public Part1Result Part_1_code()
{
return new Part1Result(){ SomeData = "foo" };
}
Consider what happens if you're if doesn't run
Then all the variables inside would be null.
You can't use variables out of scope.
You could create variables before if
and add the value in your if
int Count = 1;
foreach (DateTime Date in TestDate)
{
int someVariable;
if(Count == 1 or Count == 25){
Part_1_code that set the somevariable value;
Count = 1;
}
Pair_2_code that can access someVariable;
Count++;
}
You can initialize an anonymous type by using a dummy value:
var Count = 1;
var someAnonymous = new {Date = new DateTime(), Count = 0}; // init with dummy values
foreach (DateTime Date in TestDate)
{
if(Count == 1 || Count == 25){
// Part_1_code
Count = 1;
}
// Part_2_code
Count++;
}
Anonymous types are read-only, you cannot change the values of their properties, but you can replace the whole variable by assigning it again without changing any property.
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.
All,
I'm having an issue wrapping my head around how to find the ideal relationship between 2 values while also having to fit those items into a certain position. I honestly don't even know where to begin. I researched the knapsack problem, but there is no positional requirements.
Example:
I have $50.00 to spend on food. I need to eat 4 meals (breakfast, lunch, dinner, and a snack - which can be breakfast or lunch). Each meal has 4? properties; name, slot, calories, and cost. My goal is to eat the most calories while staying under my $50.00 allotment.
class Meal
{
public enum MealType
{
Breakfast = 1,
Lunch = 2,
Dinner = 3
}
public string Name { get; set; }
public MealType Type { get; set; }
public int Calories { get; set; }
public decimal Cost { get; set; }
public Meal(string _name, MealType _type, int _calories, decimal _cost)
{
Name = _name;
Type = _type;
Calories = _calories;
Cost = _cost;
}
}
I'm able to read in from a spreadsheet or some other source and create a Meal for each record and add it to a List. I have no idea how to read through my list (or any collection), though, and find the maximum caloric combination of 4 meals while adhering to the requirement that Meal #1 must be of type "breakfast", Meal #2 must be of type "lunch", Meal #3 must be of type "dinner", and Meal #4 can be of type "breakfast" or "lunch". Any ideas on where to begin? Thanks.
UPDATE
I ended up getting this to work - though I'm sure it is not very efficient, especially as the input list grows. Here is the hideous code (I obviously also defined a Menu class not included):
List<Meal> allMeals = Meal.GetMeals();
List<Meal> allBreakfast = new List<Meal>();
List<Meal> allLunch = new List<Meal>();
List<Meal> allDinner = new List<Meal>();
List<Meal> allSnack = new List<Meal>();
foreach (Meal meal in allMeals)
{
if (meal.MealType == Meal.MealType.Breakfast)
{
allBreakfast.Add(meal);
allSnack.Add(meal);
}
else if (meal.MealType == Meal.MealType.Lunch)
{
allLunch.Add(meal);
allSnack.Add(meal);
}
else if (meal.MealType == Meal.MealType.Dinner)
{
allDinner.Add(meal);
}
}
foreach (Meal breakfast in allBreakfast)
{
foreach (Meal lunch in allLunch)
{
foreach (Meal dinner in allDinner)
{
foreach (Meal snack in allSnack)
{
if (snack == breakfast || snack == lunch)
{
continue;
}
currMenu = new Menu(breakfast, lunch, dinner, snack);
if (currMenu.Cost < Menu.MaxCost && (maxMenu == null || currMenu.Calories > maxMenu.Calories))
{
maxMenu = currMenu;
}
}
}
}
}
In this situation, if you are not familiar with complex algorithm, you can try the brute force algo which is still feasible in the time and memory space.
We have 4 sets to store record: A, B, C, D (A: breakfast, B: lunch, C: dinner, D = A + B)
Our aim is to find Ai, Bj, Cu, Dv so as to:
1. Ai.cost + Bj.cost + Cu.cost + Dv.cost <=50
2. Ai.calo + Bj.calo + Cu.calo + Dv.calo is maximum
As in reality, we just count up to 2 decimal--> range of price is from 0.00 -> 50.00, i.e. 5000 case
1. Find all cost combination of Ai + Bj (<=50) store into array AB.
if (Ai1 + Bj1 == Ai2 + Bj2), just take combination have higher calories.
=> Complexity: O(|A| * |B|)
2. Find all cost combination of Cu + Dv (<=50) store into array CD with the same process as for AB
=> Complexity: O(|C| * |D|)
Note: size of AB and CD is 5000 elements
3. Find all combination AB[p] + CD[q] which cost is under 5000 and we can know which one got highest calories.
=> Complexity: O(|AB| * |CD| ) = O(5000 * 5000)
Totally, if using brute-force, the time complexity is O(5000 * 5000) + O(|spreadSheet size for one categories|^2).
If the spreadSheet size is <= 5000 and you are not familiar with algorithm, you can use this simple approach. Otherwise, just move ahead, algorithm is fun :)
Ok, so if you have read about Knapsack problem, and still don't know how to solve it, here is something for you to consider
The idea is simple, the array result contains all the value of money that can be reached by any Meal combination. So at first, when you doesn't buy anything, only result[50] can be reached.
Iterating through all the choices, starting from breakfast to snack, and only check for the value that can be reached, we can slowly build up the value table. For example, if breakfast has three prices(1,2,3) so the next state can only be (50-1), (50-2), (50-3) and so on. In array result, we store the maximum value of calories which can be created. So if one Breakfast set is cost 3, calo 2, and another set is cost 3, calo 4, so the value at index (50 -3) of the result array is 4.
Finally, after scanning through all of the state, the value storing in result array is the maximum value of calories that can be made.
int money = 50;// your initial money
int[] result = new int[money + 1];
for (int i = 0; i < result.length; i++) {
result[i] = -1;//-1 means cannot reach
}
result[50] = 0;//Only 50 can be reached at first
List<Meal>[] list = new List[4]; // Array for all 4 meals
// 0 is Breakfast
// 1 is lunch
// 2 for dinner
// 3 for snack
for (int i = 0; i < 4; i++) {//Iterating from breakfast to snack
int[] temp = new int[money + 1];//A temporary array to store value
for (int j = 0; j < result.length; j++) {
temp[j] = -1;
}
for (int j = 0; j < result.length; j++) {
if (result[j] != -1) {//For previous value, which can be reached
//Try all posibilites
for (int k = 0; k < list[i].size(); k++) {
int cost = list[i].get(k).cost;
int energy = list[i].get(k).energy;
if (cost <= result[j]) {
temp[j - cost] = max(temp[j - cost], result[j] + energy);
}
}
}
}
result = temp;//Need to switch these arrays.
}
int max = 0;
for(int i = 0; i < result.length; i++){
max = max(max, result[i]);
}
System.out.println(max);