C# - fair team allocation with ratings - c#

I have a list of rankings for players in a sport and would like to assign them to teams so that the distribution of ratings is as fair as possible (i.e. eliminating teams with lots of high rated players and vice versa).
Currently I am doing this but it doesn't seem to give the optimal solution:
ratingList.Sort();
ratingList.Reverse();
var team1List = ratingList.Where((r, i) => i % 2 != 0).ToList();
var team2List = ratingList.Where((r, i) => i % 2 == 0).ToList();

After sorting them in descending order try this
var team1List = ratingList.Where((r, i) => i % 2 != 0).ToList();
var team2List = ratingList.Where((r, i) => i % 2 == 0).ToList();

For the optimal solution, the idea is to consider the ratingList twice side by side
ascending vs descending and take the first half (the other one is just mirrored)
Ex:
0, 1, 2, 3, 4 | 5, 6, 7, 8, 9
9, 8, 7, 6, 5 | 4, 3, 2, 1, 0
and keep the first half
team1 team2 team1 team2 |
0, 1, 2, 3, | 4 team1
9, 8, 7, 6, | 5 team2
The evens go in team1 and the odds in team2. If we have an even number of pairs, the last pair will be redistributed between the two teams (also please note that this works only for ratingList >= 4 (it's up to you to handle for less). Also for even number of ratings I propose to exclude the middle rating and decide later what to do with it.
Considering all the above, the solution should look like this
ratingList.Sort();
var count = ratingList.Count();
// if even number of players, keep aside the one in the middle (as rating)
int? middle = null;
if (count % 2 != 0)
{
middle = ratingList[count / 2];
ratingList.RemoveAt(count / 2);
}
var ratingListDesc = ratingList.OrderByDescending(i => i).ToList();
var half = count / 2;
var take = half % 2 != 0 ? half - 1 : half;
var team1List = ratingList.Take(take).Where((r, i) => i % 2 == 0).ToList();
team1List.AddRange(ratingListDesc.Take(take).Where((r, i) => i % 2 == 0));
var team2List = ratingList.Take(take).Where((r, i) => i % 2 != 0).ToList();
team2List.AddRange(ratingListDesc.Take(take).Where((r, i) => i % 2 != 0));
// we just have to redistribute the remaining pair between each team
if (half % 2 != 0)
{
team1List.Add(ratingList[half - 1]);
team2List.Add(ratingListDesc[half - 1]);
}
if (middle.HasValue)
{
// do something, or not ...
}

Related

Sum of selected values in an int Array in c#

I'm learning how to program using c#. I'm really new to this.
My question is I'm trying to create an array that shows 10 numbers. I want my code to check which numbers below 10 are divisible for 3 or 5 and sum the total.
I've tried to use the .Sum() function but says int doesn't contain a definition for Sum. I've put using System.Linq on my program.
Does anyone have an idea how to make this sum happens?
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sum = 1 + 2;
foreach (int n in numbers)
{
if (n % 3 == 0 || n % 5 == 0)
{
int total = n.Sum();
Console.WriteLine(total);
}
else
{
Console.WriteLine("not divisible");
}
}`
So your problem is that you are trying to call .Sum() on a variable n which is of type int (you define it here: foreach (int n in numbers), and that is not a method.
Using LINQ you could do something like:
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var total = numbers.Where(n => n % 3 == 0 || n % 5 == 0).Sum();
If I understand it correct and using your code this is what you want.
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sum = 1 + 2;
int total=0;
foreach (int n in numbers)
{
if (n % 3 == 0 || n % 5 == 0)
{
int total += n;
}
else
{
Console.WriteLine("not divisible");
}
}
Console.WriteLine(total);
I moved the printing out to after the foreach so you get one result when it is done
Everybody forgot that array should contain 10 numbers but some numbers values maybe greater than 10. Only number values below 10 should be checked. So a right answer should be
var numbers = new int[] { 1, 9, 5, 6, 8, 10,4, 15, 25, 3};
var total = numbers.Where( n => (n<10) && ( n % 3 == 0 || n % 5 == 0)).Sum();

Get all subset sof given array with 'cost' restiction

I have a set of typed elements and price for each type
var array = new []
{
new Elem(0, Types.LowCost),
new Elem(1, Types.MediumCost),
new Elem(2, Types.MediumCost),
new Elem(3, Types.HightCost),
}
And prices: LowCost - 3, MediumCost - 5, HightCost - 9
How would you find all possible unique combinations of elements with restriction "sum of costs for all elements doesn't exceed a restriction"?
For example for MaxCost = 13 I expect
Elem(0) //cost 3
Elem(1) // 5
Elem(2) // 5
Elem(3) // 9
Elem(0), Elem(1) //cost 3+5=8
Elem(0), Elem(2) // 3+5=8
Elem(0), Elem(3) // 3+9=12
Elem(1), Elem(2) // 5+5 = 10
Elem(0), Elem(1), Elem(2) // cost 13
Given a dictionary of costs:
public Dictionary<Types, int> costs = new Dictionary<Types, int>()
{
{ Types.LowCost, 3 },
{ Types.MediumCost, 5 },
{ Types.HightCost, 9 },
};
I can do this:
var query =
from n in Enumerable.Range(0, 1 << array.Length).Skip(1)
let combination = array.Where((x, i) => ((n >> i) & 1) == 1).ToArray()
let cost = combination.Select(x => costs[x.Type]).Sum()
where cost <= 13
select String.Join(", ", combination.Select(x => x.Id));
That gives me:
0
1
0, 1
2
0, 2
1, 2
0, 1, 2
3
0, 3

using where to get every other number starting with the last

I have an array of numbers {3, 6, 1, 5, 5, 6} I am trying to get every other number starting with the last number.
The correct result would then be 6, 5, 6 the only way I have been able to get this to work is to use Reverse.
int[] digitList = {3, 6, 1, 5, 5,6};
var rev = digitList.Reverse().Where((x, i) => i % 2 == 0).Reverse().ToList();
// Correct results in 6,5,6
var l = digitList.Where((x, i) => i % 2 == 0).ToList();
// Incorrect results in 3,1,5
Is there a way of doing this without the Reverse? How can i tell Where() to start at the other end?
If the count is odd, then every other number from the start, if it's even then take every other number from the second one (or skip the first), that removes the need for a reverse operation. For example:
int[] digitList = { 3, 6, 1, 5, 5, 6 };
//Skip 1 if count is odd, otherwise skip zero
var skipCount = digitList.Count() % 2 == 0 ? 1 : 0;
var l = digitList
.Skip(skipCount)
.Where((x, i) => i % 2 == 0)
.ToList();
You have to check for odd/even length arrays; to amend your current code you
should change the == 0 condition:
int[] digitList = { 3, 6, 1, 5, 5, 6, 7, 8 };
var rev = digitList
.Where((x, i) => i % 2 != digitList.Length % 2) // not "== 0"
.ToList();

Feedback Loop Filtering query using LINQ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have the following scenario (based on an actual scenario that cannot be shown here). Two inputs
A number x
A series of positive integers given as IEnumerable<int>
Now I want to find all groups of three consecutive integers in the series that can divide x with no remainder, and one group cannot overlap the other.
For instance: My series is 1, 2, 3, 4, 5, 6 and user inputs x=24
Then my LINQ will give 1, 2, 3, but will not give 2, 3, 4 because those two groups will overlap in the series.
Now I could run a LINQ query that would basically run a "window" of 3 on the series and give me the several groups, and run a Where clause to find the group that will have all 3 numbers successfully dividing x. But every time I find a match, I need some kind of a negative feedback to tell my filter to omit the subsequent groups that will be overlapping to the matching one.
To understand it better, in the above example. I can generate several groups like
1, 2, 3
2, 3, 4
3, 4, 5,
and so on
then I could say
myWindowsOf3Numbers
.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0)
So I end up with code like this
var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
var x = 24;
var windows = series.Select((number, index) => index + 2 < series.Count()? new { Number1 = series[index], Number2 = series[index+1], Number3 = series[index+2] } : null )
.Where(groups => groups != null);
var matching = windows.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0);
The above will give me 1, 2, 3 and 2, 3, 4 both, but I want only the first one of the two overlapping.
Is there any LINQ-trick to do that or I have to use foreach (Like the following code)?
private class Match
{
public int N1 { get; set; }
public int N2 { get; set; }
public int N3 { get; set; }
}
var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
var x = 24;
var windows = series.Select((number, index) => index + 2 < series.Count() ? new { Number1 = series[index], Number2 = series[index + 1], Number3 = series[index + 2] } : null)
.Where(groups => groups != null);
var matches = new List<Match>();
for (var i = 0; i < (series.Count() - 2); i ++)
{
if (x % series[i] == 0 && x % series[i + 1] == 0 && x % series[i + 2] == 0)
{
matches.Add(new Match() { N1 = series[i], N2 = series[i + 1], N3 = series[i + 2] });
i += 3;
}
}
For the sake of the challenge, here is one possible "pure" LINQ solution, but frankly I'd never use something like this:
int x = 60;
var series = new [] { 1, 2, 3, 4, 5, 6 }.AsEnumerable();
var matches = series
// Create the sliding window
.Select((e, i) => new { index = i, group = series.Skip(i).Take(3).ToArray() })
// Remove the non matching
.Where(e => e.group.Length == 3 && e.group.All(v => (x % v) == 0))
// Remove the overlapping
.Aggregate(new { next = 0, result = Enumerable.Empty<int[]>() }, (prev, next) =>
next.index >= prev.next ?
new { next = next.index + 3, result = prev.result.Concat(new[] { next.group }) } :
prev).result;
Well, you said LINQ ...:
var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
var x = 24;
var matchingWindows = series
.Select((number, index) => index + 2 < series.Length ?
new { Number1 = series[index], Number2 = series[index + 1], Number3 = series[index + 2], Index = index } :
null)
.Where(groups => groups != null)
.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0)
.ToList();
int lastTakenIndex = -1;
var nonOverlapping = matchingWindows.Where(w =>
{
if (lastTakenIndex >= 0)
{
if (w.Index <= lastTakenIndex + 2) return false;
lastTakenIndex = w.Index;
return true;
}
lastTakenIndex = w.Index;
return true;
}).ToList();
It uses a lastTakenIndex (= the start index of the 3-group that was last taken that matched the condition) which is modified as a side-effect during the Where filtering.

Delete a percent of list elements

Let's say I have a list of numbers like
1 2 3 4 5 6 7 8 9 10
Now I want to delete 50% of the list so i would have now a list like
1 3 5 7 9
I don't want to remove the first 50% , so not this
6 7 8 9 10
I want to regularly delete from the list.
I'm trying to implement this in C# or JAVA.
I know that sometime is not possible to remove that percent exactly but something close will be ok.
My procent is always an integer, so is from 0 to 100 .
I'm trying to do this with an N percent for a list, how should I start?
You can use Linq:
List<int> source = new List<int>() {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Take every other item from the list
List<int> result = source
.Where((item, index) => index % 2 == 0)
.ToList();
General case should be elaborated a little bit:
int percent = 50;
List<int> result = source
.Where((item, index) =>
(index == 0) ||
(index * percent / 100) > ((index - 1) * percent / 100))
.ToList();
int halfNumOfList = myList.Count / 2;
int itemsRemoved = 0;
for (int i = 0; i < myList.Count; i++)
{
if (itemsRemoved < halfNumOfList)
{
if (i % 2 != 0)
{
myList.Remove(myList[i]);
itemsRemoved++;
}
}
}

Categories

Resources