i have a list two values.
i want to sort out with priority 1x first.
if x1 was big so sort x1 up and if x1 equal big with x1 other so sort based on x2 than smallest.
public class A
{
public float x1;
public float x2;
}
public A(float x1, float x2)
{
this.x1 = x1;
this.x2 = x2;
}
List<A> sortedA = new List<A>();
sortedA.Add(new A(5, 1));
sortedA.Add(new A(7, 2));
sortedA.Add(new A(4, 3));
sortedA.Add(new A(2, 4));
Example 1
x1 - x2
5 - 1
7 - 2
4 - 3
2 - 4
The sorted list should print as below:
7 - 2
5 - 1
4 - 3
2 - 4
Example 2 if x1 equal with x1 other.
x1 - x2
5 - 2
3 - 1
7 - 5
7 - 2
The sorted list should print as below: if x1 equal with x1 other. Priority x2 Smallest
7 - 2
7 - 5
5 - 2
3 - 1
As pointed out by some comments, OrderBy and ThenBy or OrderByDescending and ThenByDescending are probably what you are looking for
using System.Linq;
List<A> list = new List<A>();
list.Add(new A(5, 1));
list.Add(new A(7, 2));
list.Add(new A(4, 3));
list.Add(new A(2, 4));
var ordered = list
.OrderByDescending(x => x.x1)
.ThenByDescending(x => x.x2);
foreach(var val in ordered)
Console.WriteLine($"{val.x1} - {val.x2}");
Output:
C# Fiddle
You can use the List.Sort() method with a custom IComparer implementation to sort the list based on your criteria.
Here's an example implementation of the IComparer class:
class CompareA : IComparer<A>
{
public int Compare(A a1, A a2)
{
if (a1.x1 > a2.x1)
{
return -1;
}
else if (a1.x1 < a2.x1)
{
return 1;
}
else
{
if (a1.x2 < a2.x2)
{
return -1;
}
else if (a1.x2 > a2.x2)
{
return 1;
}
else
{
return 0;
}
}
}
}
Then you can use the following code to sort the list:
sortedA.Sort(new CompareA());
This will sort the list in descending order based on x1, and ascending order based on x2 in case of equal x1 values
If you want to sort existing list, just Sort it; the only thing we have to do is to explain how to compare two items a and b:
sortedA.Sort((a, b) => {
int order = b.x1.CompareTo(a.x1);
return order != 0 // if we haven't got tie ...
? order // ... return result
: a.x2.CompareTo(b.x2); // on tie compare x2's
});
Here we used a simple trick for sorting in descending order:
b.x1.CompareTo(a.x1) // descending order, note a and b swapped
a.x2.CompareTo(b.x2) // ascending order, business as usual
Related
I have a string numbers which contains 13 digits, e.g.:
string numbers = "01234567890123456781";
and I have to multiply them:
0 * 1 * 2 * 3 * ... * 7 * 8 * 1
I've a got a solution for adding the digits together:
0 + 1 + 2 + 3 + ... + 7 + 8 + 1
I convert number string to List<int> numb and then sum items of the list with a help of Linq Sum() method:
string numbers = "01234567890123456781";
List<int> numb = new List<int>();
for (int i = 0; i < numbers.Length; i++)
{
int num = int.Parse(numbers[i].ToString());
numb.Add(num);
}
for (int b = 0; b <numb.Count()-12; b++)
{
var x = numb.Skip(b).Take(13);
int a = x.Sum(); // <- it's easy to sum, but what shall I do to multiply?
Console.WriteLine(a);
}
However, Linq doesn't have any Mult() or alike method, so what can I do to multiply the items together?
Providing that the numbers contains digits [0..9] only, a simple Linq will do:
// since 0 * anything == 0, I've removed all 0's to obtain non-zero result:
// 1 * 2 * 3 * ... * 7 * 8 * 1
string numbers = "123456789123456781";
// long: int is not large enough
long result = numbers
.Select(c => (long) (c - '0'))
.Aggregate((s, a) => s * a);
Outcome:
// 14631321600
Console.Write(result);
Aggregate (custom aggregation) will do if you want to change IEnumerable<T>.Sum() from summation (as in your current code) to multiplication:
...
var x = numb.Skip(b).Take(13); //TODO: get rid of magic number 13
// instead of summation
// int a = x.Sum();
// let's use multiplication as a custom aggregation:
// please, mind overflow: int is not enough when multiplying items
long a = x
.Select(item => (long) item)
.Aggregate((s, item) => s * item);
I have two lists filled with (x, y) data points; one of the lists being the main list and the other being a list I want to compare against.
So for example, in the main list I try to find "gaps" in the data; say I'm looking at two x data points x1 = 21 and x2 = 24. The difference between those two points is greater than deltaX = 1. So what I'd like to do, is look through the second list, and find all data points between x1 = 21 and x2 = 24 to "fill in the gap".
I have something like this:
double diffX = Math.Abs(datapoints1[i + 1].X - datapoints1[i].X);
if (diffX > deltaX)
{
datapoints1.AddRange(LookBetween(datapoints1[i + 1].X, datapoints1[i].X);
}
.
.
.
private IEnumerable<PointXY> LookBetween(double upperLimit, double lowerLimit)
{
return datapoints2.Where(x => x.X < upperLimit && x.X > lowerLimit);
}
LookBetween seems to return a boolean because nothing gets added to the main list. How can I get it to return a list of the x, y values that match the criteria based on the gap of x?
It seems like you're trying to do a pairwise iteration through neighbors in datapoints1.
Using the function linked above, you might have something like:
var pairs = datapoints1.Pairwise((d1, d2) => new
{
x1 = d1.X,
x2 = d2.X,
diffX = Math.Abs(d1.X - d2.X),
});
var gaps = from pair in pairs
where pair.diffX > deltaX
from dp2 in datapoints2
where pair.x1 < dp2.X && dp2.X < pair.x2
select dp2;
Or using your LookBetween function...
var gaps = from pair in pairs
where pair.diffX > deltaX
from dp2 in LookBetween(pair.x2, pair.x1)
select dp2;
Assuming I have a list of numbers, which could be any amount, realistically over 15.
I want to separate that list of numbers into three groups depending on their size, small, medium, and large for instance.
What is the best way of achieving this?
I've written out the below, is it necessary to make my own function as per below, or is there anything existing that I can utilise in .NET?
public static List<int> OrderByThree (List<int> list)
{
list.Sort();
int n = list.Count();
int small = n / 3;
int medium = (2 * n) / 3;
int large = n;
// depending if the number is lower/higher than s/m/l,
// chuck into group via series of if statements
return list;
}
Example
Say I have a list of numbers, 1-15 for instance, I want 1-5 in small, 6-10 in medium and 11-15 in large. However I won't know the amount of numbers at the start, no dramas, using list.count I was hoping to divide for my own function.
Since you have the list sorted already, you can use some LINQ to get the results. I'm assuming a right-closed interval here.
list.Sort();
int n = list.Count();
var smallGroup = list.TakeWhile(x => (x <= n / 3)).ToList();
var middleGroup = list.Skip(smallGroup.Count).TakeWhile(x => (x <= (2 * n) / 3)).ToList();
var largeGroup = list.Skip(smallGroup.Count + middleGroup.Count).ToList();
EDIT
As Steve Padmore commented, you probably will want to return a list of lists (List<List<int>>) from your method, rather than just List<int>.
return new List<List<int>> { smallGroup, middleGroup, largeGroup };
This would be a simple way of doing it:
var result = list.GroupBy (x =>
{
if(x <= small) return 1;
if(x <= medium) return 2;
return 3;
});
Or:
var result = list.GroupBy (x => x <= small ? 1 : x <= medium ? 2 : 3);
(This does not require the list to be sorted)
I want to calculate all possible (using a certain step) distributions of a number of items. The sum has to add up to 1.
My first approach was the following:
var percentages = new List<double>(new double[3]);
while (Math.Abs(percentages.Last() - 1.0) > 0.01)
{
Increment(percentages, 0);
if (Math.Abs(percentages.Sum() - 1.0) < 0.01)
{
percentages.ForEach(x => Console.Write("{0}\t", x));
Console.WriteLine();
}
}
private void Increment(List<double> list, int i)
{
if (list.Count > i)
{
list[i] += 0.1;
if (list[i] >= 1)
{
list[i] = 0;
Increment(list, ++i);
}
}
}
Which outputs the wanted results:
1 0 0
0.9 0.1 0
0.8 0.2 0
0.7 0.3 0
0.6 0.4 0
0.5 0.5 0
0.4 0.6 0
0.3 0.7 0
0.2 0.8 0
0.1 0.9 0
0 1 0
0.9 0 0.1
..
I'm wondering how to speed up the calculation, as the number of items can become very large (>20).
Obviously I calculate a lot of distributions just to throw them away because they don't add up to 1.
Any ideas?
This works nicely for 3 sets of numbers:
var query =
from x in Enumerable.Range(0, 11)
from y in Enumerable.Range(0, 11 - x)
let z = 10 - x - y
select new [] { x / 10.0, y / 10.0, z / 10.0 };
var percentages = query.ToList();
percentages
.ForEach(ps => Console.WriteLine(String.Join("\t", ps)));
Here's a generalized version:
Func<int, int[], int[][]> generate = null;
generate = (n, ns) =>
n == 1
? new int[][]
{
ns
.Concat(new [] { 10 - ns.Sum() })
.ToArray()
}
: Enumerable
.Range(0, 11 - ns.Sum())
.Select(x =>
ns.Concat(new [] { x }).ToArray())
.SelectMany(xs => generate(n - 1, xs))
.ToArray();
var elements = 4;
var percentages =
generate(elements, new int[] { })
.Select(xs => xs.Select(x => x / 10.0).ToArray())
.ToList();
Just change the elements value to get the number of elements for the inner array.
At the risk of duplicating effort, here is a version that is fundamentally the same as the other answer. However, I already wrote it so I might as well share it. I'll also point out some differences that may or may not be important to the OP:
static void Main(string[] args)
{
Permute(1, 0.1m, new decimal[3], 0);
}
static void Permute(decimal maxValue, decimal increment, decimal[] values, int currentValueIndex)
{
if (currentValueIndex == values.Length - 1)
{
values[currentValueIndex] = maxValue;
Console.WriteLine(string.Join(", ", values));
return;
}
values[currentValueIndex] = 0;
while (values[currentValueIndex] <= maxValue)
{
Permute(maxValue - values[currentValueIndex], increment, values, currentValueIndex + 1);
values[currentValueIndex] += increment;
}
}
Notes:
I use the decimal type here. In this particular case, it avoids the need for epsilon-based checks as in the original code.
I prefer also using string.Join() rather than issuing multiple calls to Console.Write().
Also in this case the use of List<T> doesn't seem beneficial, so my implementation uses an array.
But I admit, its basic algorithm is the same.
I would turn this inside out. Keep track of the remainder, and only increment up until that remainder. You can also speed things up by setting the last element to the only value that can work. That way every combination that you look at is going to be printable.
If you organize things this way, then you will probably find it good to put the print inside the recursive function.
I don't program in C#, but it might look something like this:
var percentages = new List<double>(new double[3]);
PrintCombinations(percentages, 0, 1.0);
private void PrintCombinations(List <double> list, int i, double r) {
double x = 0.0;
if (list.Count > i + 1) {
while (x < r + 0.01) {
list[i] = x;
PrintCombinations(list, i+1, r-x);
}
}
else {
list[i] = r;
percentages.ForEach(x => Console.Write("{0}\t", x));
Console.WriteLine();
}
}
(Admittedly this does put the combinations in a different order. Fixing that is left as an exercise...)
If by 'distribution' you mean 'sum of 3 numbers in steps of 0.1 adding up to 1.0', how about this rather direct approach:
for (decimal i = 0; i< 1; i+=0.1m)
for (decimal j = 0; j < 1 - i; j+=0.1m)
{
Console.WriteLine(i + " " + j + " " + (1 - i - j) );
}
At the very outset let me express my sincere thanks to Marc Gravel,Dahlbyk and the rest for helping me to apply linq practically.
The following are few questions which I have faced in an interview to solve applying Linq. As I am not familiar with Linq I solved it without using Linq.
I appreciate the answers which helps me to solve them using Linq
Thanks in advance.
Question 1:
The Problem is to find different digits such that,in whatever order they are used to make a three-digit number,that number will not be divisible by:
3,5,7,11,13 or 17.
To ensure that there is no ambuigity,suppose the three digits
are a,b,and c.Then,none of the combination of the numbers:
say abc,acb,bac,bca,cab and cba will divide by 3,5,7,11,13 or 17.
Example :
When I take 248 none of its combination(284,428,482,842,824) will exactly divisible by 3,5,7,11,13 or 17.
public void FindingRareNumbers()
{
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
for (int k = 1; k <= 9; k++)
{
//to form the three digit
string digit = i.ToString() + j.ToString() + k.ToString();
//converting to integer
int StrToDigit = Convert.ToInt32(digit);
char[] digitcombination = digit.ToCharArray();
string PossibleCombination = "";
bool testpassed = false;
int dcount = 0;
#region different possible combinations
for (int p = 0; p <= 2; p++)
{
for (int q = 0; q <= 2; q++)
{
for (int r = 0; r <= 2; r++)
{
// The following condition avoid the repeatance
// of digit like 111,111,111
if (p != q && p != r && r != q)
{
PossibleCombination =
digitcombination[p].ToString() +
digitcombination[q].ToString() +
digitcombination[r].ToString();
int num = Convert.ToInt32(PossibleCombination);
if (num % 3 != 0 && num % 5 != 0 && num % 7 != 0
&& num % 11 != 0 && num % 11 != 0
&& num % 13 != 0 && num % 17 != 0)
{
//count is increment for 6 times
// it satisfies the condition
dcount++;
testpassed = true;
}
}
}
}
}
#endregion combination
if (testpassed && dcount==6)
{
Console.WriteLine(StrToDigit);
}
}
}
}
}
(coding is working)
Question 2:
The task is to arrange the element in matrix so that all rows,columns,and diagonals add up to the same total.(Bit problem in coding ,I am trying to solve it).
------------------
1 2 3
-----------------
4 5 6
-----------------
7 8 9
-----------------
example :
The one of solutions is as follows:
-----------
2 9 4
-----------
7 5 3
----------
6 1 8
----------
I agree that Marc's solution to your first problem is a reasonable approach. But I think there's a larger question here, which is "how do I solve problems like this in a LINQ-ish manner?"
Notice how your solution is completely "procedural" and "imperative". Your code specifies a series of steps that you would execute, one after the other, with deep loops. Each step along the way is meaningless unless you understand its place in the larger whole.
There are two ideas I like to use when solving problems with LINQ:
Describe what the program is doing logically, rather than listing a series of commands
Characterize the problem as a query against a data set rather than as a procedure to follow.
So, what's our data set? We wish to filter out some elements from the set of all combinations of three digits.
How do we filter them? Permute the digits and then perform a divisibility check on each permutation.
OK, so now we have a structure for our program:
var query = from c in ThreeDigitCombinations()
where DivisibilityCheckPasses(c)
select c;
foreach(Combination result in query) Console.WriteLine(result);
And now you can continue breaking down each of those further, solving each sub-problem using LINQ in turn.
Same goes for your "magic square" problem; you're looking for a permutation that has a certain property, so write a generator of permutations, write a filter, and execute it.
For the first:
static IEnumerable<int> Permute(int x, int y, int z)
{
yield return x * 100 + y * 10 + z;
yield return x * 100 + z * 10 + y;
yield return y * 100 + x * 10 + z;
yield return y * 100 + z * 10 + x;
yield return z * 100 + x * 10 + y;
yield return z * 100 + y * 10 + x;
}
static void Main()
{
var divs = new[] {3,5,7,11,13,17};
// combinations of 1-9
var combinations =
from x in Enumerable.Range(1, 7)
from y in Enumerable.Range(x + 1, 8 - x)
from z in Enumerable.Range(y + 1, 9 - y)
select new { x, y, z };
// permute
var qry = from comb in combinations
where !Permute(comb.x, comb.y, comb.z).Any(
i => divs.Any(d => i % d == 0))
select comb;
foreach (var answer in qry)
{
Console.WriteLine("{0}, {1}, {2}", answer.x, answer.y, answer.z);
}
}
For the second - not elegant, but it works (returns the 8 permutations of the sample):
static void Main() {
var data = Enumerable.Range(1, 9);
var magicSquares =
// generate 1st row and deduce the target
from a in data let arrA = new[] { a }
from b in data.Except(arrA) let arrB = new[] { a,b }
from c in data.Except(arrB) let arrC = new[] { a,b,c }
let target = a + b + c
// generate 2nd row and filter to target matches
from d in data.Except(arrC) let arrD = new[] { a,b,c,d }
from e in data.Except(arrD) let arrE = new[] { a,b,c,d,e }
from f in data.Except(arrE) let arrF = new[] { a,b,c,d,e,f }
where d + e + f == target
// generate 3rd row and filter to target matches
from g in data.Except(arrF) let arrG = new[] { a,b,c,d,e,f,g }
from h in data.Except(arrG) let arrH = new[] { a,b,c,d,e,f,g,h }
from i in data.Except(arrH)
where g + h + i == target
// filter columns
&& a + d + g == target
&& b + e + h == target
&& c + f + i == target
// filter diagonals
&& a + e + i == target
&& c + e + g == target
select new {a,b,c,d,e,f,g,h,i};
foreach (var row in magicSquares)
{
Console.WriteLine("{0} {1} {2}", row.a, row.b, row.c);
Console.WriteLine("{0} {1} {2}", row.d, row.e, row.f);
Console.WriteLine("{0} {1} {2}", row.g, row.h, row.i);
Console.WriteLine();
}
}