let's say that I have a table called
Items (ID int, Done int, Total int)
I can do it by two queries:
int total = m.Items.Sum(p=>p.Total)
int done = m.Items.Sum(p=>p.Done)
But I'd like to do it in one query, something like this:
var x = from p in m.Items select new { Sum(p.Total), Sum(p.Done)};
Surely there is a way to call aggregate functions from LINQ syntax...?
This will do the trick:
LINQ Query Syntax:
from p in m.Items
group p by 1 into g
select new
{
SumTotal = g.Sum(x => x.Total),
SumDone = g.Sum(x => x.Done)
};
LINQ Method Syntax:
m.Items
.GroupBy(r => 1)
.Select(g => new
{
SumTotal = g.Sum(x => x.Total),
SumDone = g.Sum(x => x.Done)
});
Notice that this solution (both syntax) returns a list of 1 item, so you might want to add at the end:
.FirstOrDefault();
To sum the table, group by a constant:
from p in m.Items
group p by 1 into g
select new {
SumTotal = g.Sum(x => x.Total),
SumDone = g.Sum(x => x.Done)
}
How about
m.Items.Select(item => new { Total = item.Total, Done = item.Done })
.Aggregate((t1, t2) => new { Total = t1.Total + t2.Total, Done = t1.Done + t2.Done });
Figuring out where to extract the sums or other aggregate in the rest of my code confused me, until I remembered that the variable I constructed was an Iqueryable. Suppose we have a table in our database composed of Orders, and we want to produce a summary for the ABC company:
var myResult = from g in dbcontext.Ordertable
group p by (p.CUSTNAME == "ABC") into q // i.e., all of ABC company at once
select new
{
tempPrice = q.Sum( x => (x.PRICE ?? 0m) ), // (?? makes sure we don't get back a nullable)
tempQty = q.Sum( x => (x.QTY ?? 0m) )
};
Now the fun part -- tempPrice and tempQty aren't declared anywhere but they must be part of myResult, no? Access them as follows:
Console.Writeline(string.Format("You ordered {0} for a total price of {1:C}",
myResult.Single().tempQty,
myResult.Single().tempPrice ));
A number of other Queryable methods could be used as well.
With a helper tuple class, either your own or—in .NET 4—the standard ones you can do this:
var init = Tuple.Create(0, 0);
var res = m.Items.Aggregate(init, (t,v) => Tuple.Create(t.Item1 + v.Total, t.Item2 + v.Done));
And res.Item1 is the total of the Total column and res.Item2 of the Done column.
This has been answered already, but the other answers will still do multiple iterations over the collection (multiple calls to Sum) or create lots of intermediate objects/Tuples which may be fine, but if it isn't, then you can create an extension method (or multiple) that does it the old-fashioned way but fits well in a LINQ expression.
Such an extension method would look like this:
public static Tuple<int, int> Sum<T>(this IEnumerable<T> collection, Func<T, int> selector1, Func<T, int> selector2)
{
int a = 0;
int b = 0;
foreach(var i in collection)
{
a += selector1(i);
b += selector2(i);
}
return Tuple.Create(a, b);
}
And you can use it like this:
public class Stuff
{
public int X;
public int Y;
}
//...
var stuffs = new List<Stuff>()
{
new Stuff { X = 1, Y = 10 },
new Stuff { X = 1, Y = 10 }
};
var sums = stuffs.Sum(s => s.X, s => s.Y);
//Calculate the total in list field values
//Use the header file:
Using System.Linq;
int i = Total.Sum(G => G.First);
//By using LINQ to calculate the total in a list field,
var T = (from t in Total group t by Total into g select g.Sum(t => t.First)).ToList();
//Here Total is a List and First is the one of the integer field in list(Total)
Using the language support for tuples introduced in C# 7.0 you can solve this using the following LINQ expression:
var itemSums = m.Items.Aggregate((Total: 0, Done: 0), (sums, item) => (sums.Total + item.Total, sums.Done + item.Done));
Full code sample:
var m = new
{
Items = new[]
{
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
new { Total = 10, Done = 1 },
},
};
var itemSums = m.Items.Aggregate((Total: 0, Done: 0), (sums, item) => (sums.Total + item.Total, sums.Done + item.Done));
Console.WriteLine($"Sum of Total: {itemSums.Total}, Sum of Done: {itemSums.Done}");
When you use group by Linq creates a new collection of items so you have two collections of items.
Here's a solution to both problems:
summing any amount of members in one iteration and
avoid duplicating your item's collection
Code:
public static class LinqExtensions
{
/// <summary>
/// Computes the sum of the sequence of System.Double values that are obtained
/// by invoking one or more transform functions on each element of the input sequence.
/// </summary>
/// <param name="source">A sequence of values that are used to calculate a sum.</param>
/// <param name="selectors">The transform functions to apply to each element.</param>
public static double[] SumMany<TSource>(this IEnumerable<TSource> source, params Func<TSource, double>[] selectors)
{
if (selectors.Length == 0)
{
return null;
}
else
{
double[] result = new double[selectors.Length];
foreach (var item in source)
{
for (int i = 0; i < selectors.Length; i++)
{
result[i] += selectors[i](item);
}
}
return result;
}
}
/// <summary>
/// Computes the sum of the sequence of System.Decimal values that are obtained
/// by invoking one or more transform functions on each element of the input sequence.
/// </summary>
/// <param name="source">A sequence of values that are used to calculate a sum.</param>
/// <param name="selectors">The transform functions to apply to each element.</param>
public static double?[] SumMany<TSource>(this IEnumerable<TSource> source, params Func<TSource, double?>[] selectors)
{
if (selectors.Length == 0)
{
return null;
}
else
{
double?[] result = new double?[selectors.Length];
for (int i = 0; i < selectors.Length; i++)
{
result[i] = 0;
}
foreach (var item in source)
{
for (int i = 0; i < selectors.Length; i++)
{
double? value = selectors[i](item);
if (value != null)
{
result[i] += value;
}
}
}
return result;
}
}
}
Here's the way you have to do the summation:
double[] result = m.Items.SumMany(p => p.Total, q => q.Done);
Here's a general example:
struct MyStruct
{
public double x;
public double y;
}
MyStruct[] ms = new MyStruct[2];
ms[0] = new MyStruct() { x = 3, y = 5 };
ms[1] = new MyStruct() { x = 4, y = 6 };
// sum both x and y members in one iteration without duplicating the array "ms" by GROUPing it
double[] result = ms.SumMany(a => a.x, b => b.y);
as you can see
result[0] = 7
result[1] = 11
Related
I have a List where each double[] has a length of 3. I would like to clean this list by leaving only those double[] having unique elements within a given tolerance (round up). For instance, a list like the one below:
1059.17 0 446.542225842081
1059.17 0 446.542564789741
1059.17 0 446.541759880305
959.167 0 579.827860527898
959.167 0 579.827847296075
Should become this for a given tolerance=two:
1059.17 0 446.54,
959.17 0 579.83,
Is there a smart way to do this in a neat way?
This should work. It uses the build-in equality comparisons of anonymous types.
List<double[]> data = ...
int tolerance = 2;
var roundedData = data
.Select(x => new {
v1 = Math.Round(x[0], tolerance),
v2 = Math.Round(x[1], tolerance),
v3 = Math.Round(x[2], tolerance)
})
.Distinct()
.Select(x => new [] { x.v1, x.v2, x.v3 })
.ToList();
Providing that array elements are always in the same order you can create your own comparer that should know how to compare double arrays :
public class MyDoubleArrComparer : IEqualityComparer<double[]>
{
public bool Equals(double[] x, double[] y)
{
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i]) return false;
}
return true;
}
public int GetHashCode(double[] obj)
{
return base.GetHashCode();
}
}
And you can create a helper method that will round numbers and remove duplicates :
public static class Helper
{
public static List<double[]> MyFilter(this List<double[]> list, int tolerance)
{
var result = list
.Select(arr =>
{
// rounds numbers with precision that is set in tolerance variable
arr = arr.Select(d => d = Math.Round(d, tolerance)).ToArray();
return arr;
}).Distinct(new MyDoubleArrComparer()) // here we use our custom comparer
.ToList();
return result;
}
}
Now we can start using our helper method :
var nums = new List<double[]>()
{
new[] {1059.17, 0, 446.542225842081},
new[] {1059.17, 0, 446.542564789741},
new[] {1059.17, 0, 446.541759880305},
new[] {959.167, 0, 579.827860527898},
new[] {959.167, 0, 579.827847296075},
};
var result = nums.MyFilter(2);
foreach (var arr in result)
{
foreach (var d in arr)
{
Console.Write(d + " ");
}
Console.WriteLine();
}
Output :
1059.17 0 446.54
959.17 0 579.83
Maybe this will work?
public List<double[]> CleanWithTolerance(List<double[]> doubleNumbersList, int tolerance)
{
var newDoublesNumbersList = new List<double[]>();
foreach(double[] doubleNumbers in doubleNumbersList)
{
var newDoublesNumbers = doubleNumbers.Select(doubleNumber => Math.Round(doubleNumber, tolerance)).ToArray();
if(newDoublesNumbersList.All(cleanDoubleNumbers => !Enumerable.SequenceEqual(cleanDoubleNumbers, newDoublesNumbers))
{
newDoublesNumbersList.Add(newDoublesNumbers);
}
}
return newDoublesNumbersList;
}
I have two linq queries, one to get confirmedQty and another one is to get unconfirmedQty.
There is a condition for getting unconfirmedQty. It should be average instead of sum.
result = Sum(confirmedQty) + Avg(unconfirmedQty)
Is there any way to just write one query and get the desired result instead of writing two separate queries?
My Code
class Program
{
static void Main(string[] args)
{
List<Item> items = new List<Item>(new Item[]
{
new Item{ Qty = 100, IsConfirmed=true },
new Item{ Qty = 40, IsConfirmed=false },
new Item{ Qty = 40, IsConfirmed=false },
new Item{ Qty = 40, IsConfirmed=false },
});
int confirmedQty = Convert.ToInt32(items.Where(o => o.IsConfirmed == true).Sum(u => u.Qty));
int unconfirmedQty = Convert.ToInt32(items.Where(o => o.IsConfirmed != true).Average(u => u.Qty));
//Output => Total : 140
Console.WriteLine("Total : " + (confirmedQty + unconfirmedQty));
Console.Read();
}
public class Item
{
public int Qty { get; set; }
public bool IsConfirmed { get; set; }
}
}
Actually accepted answer enumerates your items collection 2N + 1 times and it adds unnecessary complexity to your original solution. If I'd met this piece of code
(from t in items
let confirmedQty = items.Where(o => o.IsConfirmed == true).Sum(u => u.Qty)
let unconfirmedQty = items.Where(o => o.IsConfirmed != true).Average(u => u.Qty)
let total = confirmedQty + unconfirmedQty
select new { tl = total }).FirstOrDefault();
it would take some time to understand what type of data you are projecting items to. Yes, this query is a strange projection. It creates SelectIterator to project each item of sequence, then it create some range variables, which involves iterating items twice, and finally it selects first projected item. Basically you have wrapped your original queries into additional useless query:
items.Select(i => {
var confirmedQty = items.Where(o => o.IsConfirmed).Sum(u => u.Qty);
var unconfirmedQty = items.Where(o => !o.IsConfirmed).Average(u => u.Qty);
var total = confirmedQty + unconfirmedQty;
return new { tl = total };
}).FirstOrDefault();
Intent is hidden deeply in code and you still have same two nested queries. What you can do here? You can simplify your two queries, make them more readable and show your intent clearly:
int confirmedTotal = items.Where(i => i.IsConfirmed).Sum(i => i.Qty);
// NOTE: Average will throw exception if there is no unconfirmed items!
double unconfirmedAverage = items.Where(i => !i.IsConfirmed).Average(i => i.Qty);
int total = confirmedTotal + (int)unconfirmedAverage;
If performance is more important than readability, then you can calculate total in single query (moved to extension method for readability):
public static int Total(this IEnumerable<Item> items)
{
int confirmedTotal = 0;
int unconfirmedTotal = 0;
int unconfirmedCount = 0;
foreach (var item in items)
{
if (item.IsConfirmed)
{
confirmedTotal += item.Qty;
}
else
{
unconfirmedCount++;
unconfirmedTotal += item.Qty;
}
}
if (unconfirmedCount == 0)
return confirmedTotal;
// NOTE: Will not throw if there is no unconfirmed items
return confirmedTotal + unconfirmedTotal / unconfirmedCount;
}
Usage is simple:
items.Total();
BTW Second solution from accepted answer is not correct. It's just a coincidence that it returns correct value, because you have all unconfirmed items with equal Qty. This solution calculates sum instead of average. Solution with grouping will look like:
var total =
items.GroupBy(i => i.IsConfirmed)
.Select(g => g.Key ? g.Sum(i => i.Qty) : (int)g.Average(i => i.Qty))
.Sum();
Here you have grouping items into two groups - confirmed and unconfirmed. Then you calculate either sum or average based on group key, and summary of two group values. This also neither readable nor efficient solution, but it's correct.
Currently, this is just something I am curious about, I don't have any code I am working on but I am wondering how this could be achieved...
Lets say for example that I have an application that tracks the results of all the football teams in the world. What I want to be able to do is to identify the longest "win" streak for any given team.
I imagine I would most likely have some sort of data table like so:
MatchDate datetime
TeamA string
TeamB string
TeamAGoals int
TeamBGoals int
So what I would want to do for example is find the longest win streak where TeamA = "My Team" and obviously this would mean TeamAGoals must be greater than TeamBGoals.
As I have said, this is all just for example. It may be better for a different DB design for something like this. But the root question is how to calculate the longest streak/run of matching results.
This is an old question now, but I just had to solve the same problem myself, and thought people might be interested in a fully LINQ implementation of Rawling's LongestStreak extension method. This uses Aggregate with a seed and result selector to run through the list.
public static int LongestStreak<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
return source.Aggregate(
new {Longest = 0, Current = 0},
(agg, element) => predicate(element) ?
new {Longest = Math.Max(agg.Longest, agg.Current + 1), Current = agg.Current + 1} :
new {agg.Longest, Current = 0},
agg => agg.Longest);
}
There's no out-of-the-box LINQ method to count streaks, so you'll need a custom LINQy method such as
public static int LongestStreak<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
int longestStreak = 0;
int currentStreak = 0;
foreach (TSource s in source)
{
if (predicate(s))
currentStreak++;
else
{
if (currentStreak > longestStreak) longestStreak = currentStreak;
currentStreak = 0;
}
}
if (currentStreak > longestStreak) longestStreak = currentStreak;
return longestStreak;
}
Then, to use this, first turn each "match result" into a pair of "team results".
var teamResults = matches.SelectMany(m => new[] {
new {
MatchDate = m.MatchDate,
Team = m.TeamA,
Won = m.TeamAGoals > m.TeamBGoals },
new {
MatchDate = m.MatchDate,
Team = m.TeamB,
Won = m.TeamBGoals > m.TeamAGoals }
});
Group these by team.
var groupedResults = teamResults.GroupBy(r => r.Team);
Then calculate the streaks.
var streaks = groupedResults.Select(g => new
{
Team = g.Key,
StreakLength = g
// unnecessary if the matches were ordered originally
.OrderBy(r => r.MatchDate)
.LongestStreak(r => r.Won)
});
If you want the longest streak only, use MoreLinq's MaxBy; if you want them all ordered, you can use OrderByDescending(s => s.StreakLength).
Alternatively, if you want to do this in one pass, and assuming matches is already ordered, using the following class
class StreakAggregator<TKey>
{
public Dictionary<TKey, int> Best = new Dictionary<TKey, int>();
public Dictionary<TKey, int> Current = new Dictionary<TKey, int>();
public StreakAggregator<TKey> UpdateWith(TKey key, bool success)
{
int c = 0;
Current.TryGetValue(key, out c);
if (success)
{
Current[key] = c + 1;
}
else
{
int b = 0;
Best.TryGetValue(key, out b);
if (c > b)
{
Best[key] = c;
}
Current[key] = 0;
}
return this;
}
public StreakAggregator<TKey> Finalise()
{
foreach (TKey k in Current.Keys.ToArray())
{
UpdateWith(k, false);
}
return this;
}
}
you can then do
var streaks = teamResults.Aggregate(
new StreakAggregator<string>(),
(a, r) => a.UpdateWith(r.Team, r.Won),
(a) => a.Finalise().Best.Select(kvp =>
new { Team = kvp.Key, StreakLength = kvp.Value }));
and OrderBy or whatever as before.
You can get all results of team with single query:
var results = from m in Matches
let homeMatch = m.TeamA == teamName
let awayMatch = m.TeamB == teamName
let hasWon = (homeMatch && m.TeamAGoals > m.TeamBGoals) ||
(awayMatch && m.TeamBGoals > m.TeamAGoals)
where homeMatch || awayMatch
orderby m.MatchDate
select hasWon;
Then just do simple calculation of longest streak:
int longestStreak = 0;
int currentStreak = 0;
foreach (var hasWon in results)
{
if (hasWon)
{
currentStreak++;
if (currentStreak > longestStreak)
longestStreak = currentStreak;
continue;
}
currentStreak = 0;
}
You can use it as is, extract to method, or create IEnumerable extension for calculating longest sequence in results.
You could make use of string.Split. Something like this:
int longestStreak =
string.Concat(results.Select(r => (r.ours > r.theirs) ? "1" : "0"))
.Split(new[] { '0' })
.Max(s => s.Length);
Or, better, create a Split extension method for IEnumerable<T> to avoid the need to go via a string, like this:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> items, Predicate<T> p)
{
while (true)
{
items = items.SkipWhile(i => !p(i));
var trueItems = items.TakeWhile (i => p(i)).ToList();
if (trueItems.Count > 0)
{
yield return trueItems;
items = items.Skip(trueItems.Count);
}
else
{
break;
}
}
}
You can then simply do this:
int longestStreak = results.Split(r => r.ours > r.theirs).Max(g => g.Count());
I have a list of lists of dynamic which is currently being filtered through this:
var CPUdataIWant = from s in rawData
where s.stat.Contains("CPU")
select s;
//CPUDataIWant is a List<List<dynamic>>.
I have 86000 values in each inner list.
And what I need to do, is group the values into groups of 3, select the max of that group, and insert that into another list of List of dynamic, or just filter it out of CPUDataIWant.
So an example of what I want would be:
Raw data = 14,5,7,123,5,1,43,87,9
And my processed value would be:
ProceData = [14,5,7], [123,5,1], [43,87,9]
ProceData = [14,123,87]
Doesn't have to be using linq but the easier the better.
EDIT: Ok I explained what a wanted a bit poorly.
here's what I have:
List<List<object>>
In this List, I'll have X amount of Lists called A.
In A I'll have 86000 values, let's say they're ints for now.
What I'd like, is to have
List<List<object>>
But instead of 86000 values in A, I want 28700, which would be made from the max of every 3 values in A.
IEnumerable<int> filtered = raw.Select((x, i) => new { Index = i, Value = x }).
GroupBy(x => x.Index / 3).
Select(x => x.Max(v => v.Value));
or, if you plan to use it more often
public static IEnumerable<int> SelectMaxOfEvery(this IEnumerable<int> source, int n)
{
int i = 0;
int currentMax = 0;
foreach (int d in source)
{
if (i++ == 0)
currentMax = d;
else
currentMax = Math.Max(d, currentMax);
if (i == n)
{
i = 0;
yield return currentMax;
}
}
if (i > 0)
yield return currentMax;
}
//...
IEnumerable<int> filtered = raw.SelectMaxOfEvery(3);
Old-school way of doing things makes it quite simple (although it's not as compact as LINQ):
// Based on this spec: "CPUDataIWant is a List<List<dynamic>>"
// and on the example, which states that the contents are numbers.
//
List<List<dynamic>> filteredList = new List<List<dynamic>>();
foreach (List<dynamic> innerList in CPUDataIWant)
{
List<dynamic> innerFiltered = new List<dynamic>();
// if elements are not in multiples of 3, the last one or two won't be checked.
for (int i = 0; i < innerList.Count; i += 3)
{
if(innerList[i+1] > innerList[i])
if(innerList[i+2] > innerList[i+1])
innerFiltered.Add(innerList[i+2]);
else
innerFiltered.Add(innerList[i+1]);
else
innerFiltered.Add(innerList[i]);
}
filteredList.Add(innerFiltered);
}
This should give the desired result:
var data = new List<dynamic> { 1, 2, 3, 3, 10, 1, 5, 2, 8 };
var firsts = data.Where((x, i) => i % 3 == 0);
var seconds = data.Where((x, i) => (i + 2) % 3 == 0);
var thirds = data.Where((x, i) => (i + 1) % 3 == 0);
var list = firsts.Zip(
seconds.Zip(
thirds, (x, y) => Math.Max(x, y)
),
(x, y) => Math.Max(x, y)
).ToList();
List now contains:
3, 10, 8
Or generalized to an extension method:
public static IEnumerable<T> ReduceN<T>(this IEnumerable<T> values, Func<T, T, T> map, int N)
{
int counter = 0;
T previous = default(T);
foreach (T item in values)
{
counter++;
if (counter == 1)
{
previous = item;
}
else if (counter == N)
{
yield return map(previous, item);
counter = 0;
}
else
{
previous = map(previous, item);
}
}
if (counter != 0)
{
yield return previous;
}
}
Used like this:
data.ReduceN(Math.Max, 3).ToList()
If you felt a need to use Aggregate you could do it like this:
(tested wiht LinqPad)
class Holder
{
public dynamic max = null;
public int count = 0;
}
void Main()
{
var data = new List<dynamic>
{new { x = 1 }, new { x = 2 }, new { x = 3 },
new { x = 3 }, new { x = 10}, new { x = 1 },
new { x = 5 }, new { x = 2 }, new { x = 1 },
new { x = 1 }, new { x = 9 }, new { x = 3 },
new { x = 11}, new { x = 10}, new { x = 1 },
new { x = 5 }, new { x = 2 }, new { x = 12 }};
var x = data.Aggregate(
new LinkedList<Holder>(),
(holdList,inItem) =>
{
if ((holdList.Last == null) || (holdList.Last.Value.count == 3))
{
holdList.AddLast(new Holder { max = inItem, count = 1});
}
else
{
if (holdList.Last.Value.max.x < inItem.x)
holdList.Last.Value.max = inItem;
holdList.Last.Value.count++;
}
return holdList;
},
(holdList) => { return holdList.Select((h) => h.max );} );
x.Dump("We expect 3,10,5,9,11,12");
}
I have class like:
class SortNode
{
public Int32 m_valRating = 0;
public SortNode(Int32 valRating)
{
this.m_valRating = valRating;
}
}
and some list refSortNodeList:
List<SortNode> refSortNodeList = new List<SortNode>();
Random refRandom = new Random();
for (int i = 0; i < 100; ++i)
{
refSortNodeList.Add(new SortNode(refRandom.Next(-10, 30)));
}
foreach (var varSortNode in refSortNodeList)
{
Console.WriteLine("SortNode rating is {0}", varSortNode.m_valRating);
}
How to sort easily my refSortNodeList by m_valRating field? Or maybe I need to use some another List class?
list.Sort((x,y) =>
x.m_valRating.CompareTo(y.m_valRating));
In-place:
refSortNodeList.Sort(
(x, y) =>
x == null ? (y == null ? 0 : -1)
: (y == null ? 1 : x.m_valRating.CompareTo(y.m_valRating))
);
Creating a new enumeration:
var newEnum = refSortNodeList.OrderBy(x => x.m_valRating);
Creating a new list:
var newList = refSortNodeList.OrderBy(x => x.m_valRating).ToList();
In-place is fastest and most memory efficient, but no good if you want to also retain the old list.
The next is faster than the last and gives results as they go, but you have to re-do the sort to use it again, in which case the third is the one to go for.
Use Linq order by.
var mySortedList = refSortNodeList.OrderBy(x => x.m_valRating);
Here is a real live example where I am pulling a list from a database but it is exactly the same concept.
vendorProducts = (from vp in db.COMPANIES_VND_PRODUCTS
join p in db.CT_CT_INV_CLASSES on vp.CLASS_ID equals p.CLASS_ID
join m in db.CT_CT_MODALITY_CODES on vp.MODALITY_ID equals m.MODALITY_ID
where vp.COMPANY_ID == companyId
select new ProductTypeModality
{
Active = p.ACTIVE.Equals("Y") ? true : false,
BioMedImaging = p.BIOMED_IMAGING,
Code = p.CLASS_CODE,
Description = p.DESCRIPTION,
Id = p.CLASS_ID,
PricingMargin = p.PRICING_MARGIN,
ModalityCode = m.MODALITY_CODE,
ModalityId = m.MODALITY_ID,
VendorId = companyId
}).OrderBy(x => x.Code).ToList<ProductTypeModality>();
Implement IComparable<T>
You can use Linq for basic sorts:
refSortNodeList.OrderBy(n => n.m_valRating);
If you need more complex sorting your will need to implement IComparable to use the built in sorting.
Try this:
refSortNodeList.Sort(new delgate(SortNode x, SortNode y)
{
return x.CompareTo(y);
}
);
It's easy using linq:
var newlist = refSortNodeList.sort( n => n.m_valRating );
List<SortNode> refSortNodeList = new List<SortNode> ();
Random refRandom = new Random ();
for (int i = 0; i < 100; ++i) {
refSortNodeList.Add (new SortNode (refRandom.Next (-10, 30)));
}
// Use this (Linq) if you're using .NET 3.5 or above.
var sortedList = refSortNodeList.OrderBy (node => node.m_valRating);
foreach (var varSortNode in sortedList) {
Console.WriteLine ("SortNode rating is {0}", varSortNode.m_valRating);
}
// Use this otherwise (e.g. .NET 2.0)
refSortNodeList.Sort (
delegate (SortNode n1, SortNode n2) {
return n1.m_valRating.CompareTo (n2.m_valRating);
}
);
foreach (var varSortNode in refSortNodeList) {
Console.WriteLine ("SortNode rating is {0}", varSortNode.m_valRating);
}