Working on C#.NET.
I have this list:
List<Tuple<string, float>> sort = new List<Tuple<string, float>>();
I want to sort this list by the float value. Eg if the list is like this:
a,45
b,2
s,32
se,83.21
te,84
s3,9.5
f,7
I want it to be sorted in a descending order, like this:
te,84
se,83.21
a,45
s,32
s3,9.5
f,7
b,2
If you want to sort the list inplace, you can use the Sort method that takes Comparison<T> argument.
To sort by the Tuple.Item2 in ascending order, you can use
sort.Sort((a, b) => a.Item2.CompareTo(b.Item2));
To sort in descending order, just swap a and b:
sort.Sort((a, b) => b.Item2.CompareTo(a.Item2));
You wouldn't sort the list - you'd create a new list which contains the same items, but is sorted.
var sorted = sort.OrderByDescending(t => t.Item2).ToList();
Here is an easy way to sort the list:
sort = sort.OrderByDescending(s => s.Item2).ToList();
If you don't want to create a new list you can use the IComparer<> interface to create a customer comparer.
public class MyCompare : IComparer<Tuple<string, float>>
{
public int Compare(Tuple<string, float> x, Tuple<string, float> y)
{
return y.Item2.CompareTo(x.Item2);
}
}
... then you would use it like this ...
sort.Sort(new MyCompare());
Related
I'm trying to order a list (will refer to this list as result) by a value in another list (Redeems).
The result list contains the Redeems list, and I want to order result by the field "SumChosenYear" in the "Redeems" list and get top 20. This is what I've managed to get, and in theory I think it should work.
result = result
.OrderByDescending(input => input.Redeems
.Select(input2 => input2.SumChosenYear)
.ToList())
.Take(20)
.ToList();
However it throws an exception saying "Atleast one object implement IComparable". Why does this happen?
This line:
input.Redeems
.Select(input2 => input2.SumChosenYear)
.ToList()
returns you a List and because List does not implement IComparable you cannot put this lambda inside this overload of OrderByDescending extension.
You have basically two options:
First option
Cretae your custom implementation of IComparer for this list (assuming SumChosenYear property is an int for this purpose):
public class SumChosenYearListComparer : IComparer<List<int>>
{
public int Compare(List<int> x, List<int> y)
{
//Your custom comparison...
}
}
and then use it with this overload of OrderByDescending extension:
var result = result
.OrderByDescending(input => input.Redeems
.Select(input2 => input2.SumChosenYear)
.ToList(), new SumChosenYearListComparer())
.Take(20)
.ToList();
Second option
You can choose which item in this list you want to use in the comparison(maybe the max, min, first or last value or maybe even the sum of all the items).
Assuming you want to comapre using the max value in the list your code could look something like this:
var result = result
.OrderByDescending(input => input.Redeems
.Max(input2 => input2.SumChosenYear))
.Take(20)
.ToList();
I have
SortedList<string, object> testIds = new SortedList<string, object>();
And I neet it sort in descending order.
I used for sorting next construction:
testIds.ToList().Sort(delegate(KeyValuePair<string, object>x, KeyValuePair<string, object>y)
{
return x.Key.CompareTo(y.Key)*-1;
});
But it did not help me.Can you give me some advice how to solve this problem?
Although SortedList<K,V> sorts in ascending order by default, it provides a constructor that takes a custom IComparer<K> that lets you switch the order to whatever you need.
Implement IComparer<string> that inverts the result of the regular comparison, and give it to the constructor of SortedList<K,V>:
class ReverseComparer : IComparer<string> {
public int Compare(string x, string y) {
return -x.CompareTo(y);
}
}
var testIds = new SortedList<string,object>(new ReverseComparer());
You can write the same thing in a single line, without making a named class for it:
var testIds = new SortedList<string,object>(
// Note how the negation is replaced with reversing the order of comparison
Comparer<string>.Create((x, y) => y.CompareTo(x))
);
As pointed out by dasblinkenlight, you should use the constructor overload that takes an IComparer<T>.
However, if this is a one time thing, you're better off using Comparer<T>.Create, instead of creating a whole new class just for this.
var comparer = Comparer<string>.Create((x, y) => y.CompareTo(x));
var testIds = new SortedList<string,object>(comparer);
Also, when comparing items in reverse order, the convention is to compare y with x, instead of comparing x with y and inverting the result.
Just use Reverse. Let's suppose you have a orderedlist OrigOrderedList, then
SortedList<string, object> testIds = OrigOrderedList.Reverse() // should do the work
static void Main(string[] args)
{
SortedList<string, object> test1 = new SortedList<string, object>();
test1.Add("a", "A");
test1.Add("b", "B");
test1.Add("c", "C");
Console.WriteLine(String.Join(", ", test1.Select(x => x.Key)));
Console.WriteLine(String.Join(", ", test1.Reverse().Select(x => x.Key)));
}
In C#, I have an object type 'A' that contains a list of key value pairs.
The key value pairs is a category string and a value string.
To instantiate object type A, I would have to do the following:
List<KeyValuePair> keyValuePairs = new List<KeyValuePair>();
keyValuePairs.Add(new KeyValuePair<"Country", "U.S.A">());
keyValuePairs.Add(new KeyValuePair<"Name", "Mo">());
keyValuePairs.Add(new KeyValuePair<"Age", "33">());
A a = new A(keyValuePairs);
Eventually, I will have a List of A object types and I want to manipulate the list so that i only get unique values and I base it only on the country name. Therefore, I want the list to be reduced to only have ONE "Country", "U.S.A", even if it appears more than once.
I was looking into the linq Distinct, but it does not do what I want because it I can't define any parameters and because it doesn't seem to be able to catch two equivalent objects of type A. I know that I can override the "Equals" method, but it still doesn't solve the my problem, which is to render the list distinct based on ONE of the key value pairs.
To expand upon Karl Anderson's suggestion of using morelinq, if you're unable to (or don't want to) link to another dll for your project, I implemented this myself awhile ago:
public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> source, Func<T, U>selector)
{
var contained = new Dictionary<U, bool>();
foreach (var elem in source)
{
U selected = selector(elem);
bool has;
if (!contained.TryGetValue(selected, out has))
{
contained[selected] = true;
yield return elem;
}
}
}
Used as follows:
collection.DistinctBy(elem => elem.Property);
In versions of .NET that support it, you can use a HashSet<T> instead of a Dictionary<T, Bool>, since we don't really care what the value is so much as that it has already been hashed.
Check out the DistinctBy syntax in the morelinq project.
A a = new A(keyValuePairs);
a = a.DistinctBy(k => new { k.Key, k.Value }).ToList();
You need to select the distinct property first:
Because it's a list inside a list, you can use the SelectMany. The SelectMany will concat the results of subselections.
List<A> listOfA = new List<A>();
listOfA.SelectMany(a => a.KeyValuePairs
.Where(keyValue => keyValue.Key == "Country")
.Select(keyValue => keyValue.Value))
.Distinct();
This should be it. It will select all values where the key is "Country" and concat the lists. Final it will distinct the country's. Given that the property KeyValuePairs of the class A is at least a IEnumerable< KeyValuePair< string, string>>
var result = keyValuePairs.GroupBy(x => x.Key)
.SelectMany(g => g.Key == "Country" ? g.Distinct() : g);
You can use the groupby statement. From here you can do all kind off cool stuf
listOfA.GroupBy(i=>i.Value)
You can groupby the value and then sum all the keys or something other usefull
I have a class that is defined like this:
class A
{
int contractID;
string name;
string blah;
etc...
}
Multiple ClassA are stored stored in List(). I and to create a List based off all the ContractID's in List. Is there a way in LINQ to be able to do this instead of iterating through List()?
You can use the Select extension method to create a projection of the contractID. Like:
var listOfClass = new List<ClassA>(); //Or however you get your list.
var contractIDs = listOfClass.Select(x => x.contractID).ToList();
var onlyContractIDs = myList.Select(x => x.contractID).ToList()
List<ClassA> input = ...;
List<int> output = input.Select(a => a.contractID).ToList();
Select is a generic method. Explicitly specified, it would be Select<ClassA, int>, specifying the input and output types.
The ToList() at the end converts from an IEnumerable<int> to a List<int>, and it does the iteration over the input list now, rather than when the IEnumerable<int> is enumerated.
If you have a List you can make a List with LINQ like this
List<int> contractIDs = mycollection.Select(a => a.ContractID).ToList();
var list = new List<ClassA>();
...
list.Select(a => a.ContractID);
In my program, I have a class like this:
Class Customer{
double Start;
double Finish;
double Wait;
}
and I created an array of this class:
Customer[] customer = new Customer[300];
How I can sort this array according to Start values Descending or Ascending?
Thanks...
You could use the Array.Sort method to sort the array in-place:
Array.Sort(customer, (x, y) => x.Start.CompareTo(y.Start));
or in descending order
Array.Sort(customer, (x, y) => y.Start.CompareTo(x.Start));
If would prefer to use a List of Customer, however you can apply the same function on the array:
List<Customer> customerList = new List<Customer>;
var orderedCustomerList = customerList.OrderBy(item => item.Start);
Refer to:
Enumerable.OrderBy Method
Enumerable.OrderByDescending Method
In ascending order by Start:
var sortedCustomers = customer.OrderBy(c => c.Start);
And descending order by Start:
var sortedCustomers = customer.OrderByDescending(c => c.Start);
you need to use icomparer and you need to write your custom code after implementing icomparer in your class
you need to implement IComparable for your Customer class.
http://msdn.microsoft.com/en-us/library/system.icomparable%28v=vs.80%29.aspx
C# Tutorial - Sorting Algorithms
Sorting algorithm
You can also use LINQ Dynamic Sort With LINQ
How to sort an array of object by a specific field in C#?