How does CompareTo sort a list? - c#

Below, a list l that contains a list of Product with Name and Price properties.
The list can be sort alphabetically by the following class ProductNameComparer which implements IComparar.
List<Product> l = p.GetList();
l.Sort(new ProductNameComparer());
MessageBox.Show(l[0].Name);
public class ProductNameComparer : IComparer<Product>
{
public int Compare(Product x, Product y)
{
return x.Name.CompareTo(y.Name);
}
}
I do not understand how the list is being sorted. According to MSDN CompareTo returns an Int32 type value of less than zero, zero, or greater than zero. If I have:
string c = "Apple";
string d = "Orange";
return c.CompareTo(d)
The function will return "-1".
But if I replace l.Sort(-1) instead of l.Sort(new ProductNameComparer()) the code doesn't compile
Also why would Compare(Product x, Product y) takes only two Products as argument and yet managed to compare and sort a list (>2) of products?

The Sort method doesn't just call Compare once - it calls it multiple times, whenever it needs to compare two items. It's a general sort algorithm which is able to sort any collection of items, so long as it can compare any two of them in a consistent way.
The code doesn't compile if you try to call l.Sort(-1) because that's just trying to pass in an integer - what would that even mean?
You need to understand that you're not giving the Sort method one comparison result - you're giving it the ability to compare whichever items it needs to.

For the purpose of demonstration here is a possible implementation of the Sort method (a highly inefficient one, I know):
public void Sort(System.Collections.Generic.IComparer<T> comparer)
{
for (int i = 0; i < this.Count - 1; i++)
{
for (int j = i + 1; j < this.Count; j++)
{
if (comparer.Compare(this[i], this[j]) > 0)
{
T tmp = this[i];
this[i] = this[j];
this[j] = tmp;
}
}
}
}

The Sort method overload used in your example (new ProductNameComparer()) requires the parameter to implement an IComparer interface. Calling Sort(-1) won't work since int doesn't implement this interface. As per #JonSkeet, the result of calling CompareTo() is used by the sorting strategy to order the list.

Related

C# - Creating a recursive function to calculate the sum of a list. Is it possible using only the list as the only parameter?

So in my attempt to start learning c# one challenge I've come across is to create a recursive function that will calculate the sum of a list. I'm wondering if it's possible to do this using a list as the only argument of the function? Or would I need to apply an index size as well to work through the list?
int addRecursively(List<int> numList)
{
int total = numList[0];
if (numList.Count > 1)
{
numList.RemoveAt(0);
return total += addRecursively(numList);
}
Console.WriteLine(total);
return total;
}
List<int> numbers = new<List<int> {1,2,3,4,5,6,7,8};
addRecursively(numbers); //returns only the last element of whichever list I enter.
I was hoping by assigning the total to the first index of the list before deleting the first index of the list that when passed into the next instance of the function the index of each element in the list would move down one, allowing me to get each value in the list and totalling them up. However using the function will only ever return the last element of whichever list of integers I enter.
My thought process came from arrays and the idea of the shift method on an array in JS, removing the first element and bringing the whole thing down.
Am I attempting something stupid here? Is there another similar method I should be using or would I be better off simply including a list size as another parameter?
Thanks for your time
So in my attempt to start learning c# one challenge I've come across is to create a recursive function that will calculate the sum of a list. I'm wondering if it's possible to do this using a list as the only argument of the function? Or would I need to apply an index size as well to work through the list?
That's a great exercise for a beginner. However, you would never, ever do this with a List<int> in a realistic program. First, because you'd simply call .Sum() on it. But that's a cop-out; someone had to write Sum, and that person could be you.
The reason you would never do this recursively is List<T> is not a recursive data structure. As you note, every time you recurse there has to be something different. If there is not something different then you have an unbounded recursion!
That means you have to change one of the arguments, either by mutating it, if it is a reference type, or passing a different argument. Neither is correct in this case where the argument is a list.
For a list, you never want to mutate the list, by removing items, say. You don't own that list. The caller owns the list and it is rude to mutate it on them. When I call your method to sum a list, I don't want the list to be emptied; I might want to use it for something else.
And for a list, you never want to pass a different list in a recursion because constructing the new list from the old list is very expensive.
(There is also the issue of deep recursion; presumably we wish to sum lists of more than a thousand numbers, but that will eat up all the stack space if you go with a recursive solution; C# is not a guaranteed-tail-recursive language like F# is. However, for learning purposes let's ignore this issue and assume we are dealing with only small lists.)
Since both of the techniques for avoiding unbounded recursions are inapplicable, you must not write recursive algorithms on List<T> (or, as you note, you must pass an auxiliary parameter such as an index, and that's the thing you change). But your exercise is still valid; we just have to make it a better exercise by asking "what would we have to change to make a list that is amenable to recursion?"
We need to change two things: (1) make the list immutable, and (2) make it a recursively defined data structure. If it is immutable then you cannot change the caller's data by accident; it's unchangeable. And if it is a recursively defined data structure then there is a natural way to do recursion on it that is cheap.
So this is your new exercise:
An ImmutableList is either (1) empty, or (2) a single integer, called the "head", and an immutable list, called the "tail". Implement these in the manner of your choosing. (Abstract base class, interface implemented by multiple classes, single class that does the whole thing, whatever you think is best. Pay particular attention to the constructors.)
ImmutableList has three public read-only properties: bool IsEmpty, int Head and ImmutableList Tail. Implement them.
Now we can define int Sum(ImmutableList) as a recursive method: the base case is the sum of an empty list is zero; the inductive case is the sum of a non-empty list is the head plus the sum of the tail. Implement it; can you do it as a single line of code?
You will learn much more about C# and programming in a functional style with this exercise. Use iterative algorithms on List<T>, always; that is what it was designed for. Use recursion on data structures that are designed for recursion.
Bonus exercises:
Write Sum as an extension method, so that you can call myImmutableList.Sum().
Sum is a special case of an operation called Aggregate. It returns an integer, and takes three parameters: an immutable list, an integer called the accumulator, and a Func<int, int, int>. If the list is empty, the result is the accumulator. Otherwise, the result is the recursion on the tail and calling the function on the head and the accumulator. Write a recursive Aggregate; if you've done it correctly then int Sum(ImmutableList items) => Aggregate(items, 0, (acc, item) => acc + item); should be a correct implementation of Sum.
Genericize ImmutableList to ImmutableList<T>; genericize Aggregate to Aggregate<T, R> where T is the list element type and R is the accumulator type.
Try this way:
int addRecursively(List<int> lst)
{
if(lst.Count() == 0) return 0;
return lst.Take(1).First() + addRecursively(lst.Skip(1).ToList());
}
one more example:
static public int RecursiveSum(List<int> ints)
{
int nextIndex = 0;
if(ints.Count == 0)
return 0;
return ints[0] + RecursiveSum(ints.GetRange(++nextIndex, ints.Count - 1));
}
These are some ways to get the sum of integers in a list.
You don't need a recursive method, it spends more system resources when it isn't needed.
class Program
{
static void Main(string[] args)
{
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
int sum1 = numbers.Sum();
int sum2 = GetSum2(numbers);
int sum3 = GetSum3(numbers);
int sum4 = GetSum4(numbers);
}
private static int GetSum2(List<int> numbers)
{
int total = 0;
foreach (int number in numbers)
{
total += number;
}
return total;
}
private static int GetSum3(List<int> numbers)
{
int total = 0;
for (int i = 0; i < numbers.Count; i++)
{
total += numbers[i];
}
return total;
}
private static int GetSum4(List<int> numbers)
{
int total = 0;
numbers.ForEach((number) =>
{
total += number;
});
return total;
}
}

List is taking too much time

I have been writing a program which has a list of 100,000 elements I have to process all the elements with different conditions. This does not take much time 3sec at most. After this I have a list of valid entries and my orignal list which had 100000 elements. The new list usualy has a size of 6K - 7K. The main problem is when I use List.Remove function or any other way to remove the invalid elements from the orignal list with 100K elements its too slow.
Please guide if I should use any thing else then the LIST or there is something that I can do with this code also.
I am including all codes I tried.
for( int k = 0; k < initialList.Count;k++)
{
combo c = initialList.ElementAt(k);
if(invalidEntries.Contains(c))
{
smartString.Append(c.number1.ToString());
smartString.Append(c.number2.ToString());
smartString.Append(c.number3.ToString());
smartString.Append(c.number4.ToString());
smartString.Append(c.number5.ToString());
smartString.Append(" Sum : ");
smartString.Append(c.sum.ToString());
smartString.AppendLine();
InvalidCombo.AppendText(smartString.ToString());
smartString.Clear();
}
else
{
smartString.Append(c.number1.ToString());
smartString.Append(c.number2.ToString());
smartString.Append(c.number3.ToString());
smartString.Append(c.number4.ToString());
smartString.Append(c.number5.ToString());
smartString.Append(" Sum : ");
smartString.Append(c.sum.ToString());
smartString.AppendLine();
validCombo.AppendText(smartString.ToString());
smartString.Clear();
}
}
Also
for(int k=0;k<100000;k++)
{
combo c = initialList.ElementAt(k);
if (!invalidEntries.Contains(c))
validEntries.Add(c);
}
I have also tried the .remove functions but i think list cant take it. so any suggestions/solutions?
I'm a big fan of the structs, but you must be very careful when you work with a struct like yours. The List<T> methods that rely on equality (Contains, IndexOf, Remove) may not work and should not be used. Same for HashSet<T> and similar.
The best for your case would be to combine the processing with the removal. And the fastest way to do a removal from a List<T> is to not use it's item remove related (Remove/RemoveAt) methods! :-) Instead, you "compact" the list by keeping the items that should remain (and their count) at the beginning of the list, and then just use RemoveRange method to cut the unnecessary items at the end of the list. This is very efficient and avoids all the data block moving which happens when you use the "normal" list remove methods. Here is a sample code based on your struct definition:
public struct combo { public int number1; public int number2; public int number3; public int number4; public int number5; public int sum; public bool invalid; }
void ProcessList(List<combo> list)
{
int count = 0;
for (int i = 0; i < list.Count; i++)
{
var item = list[i];
ProcessItem(ref item);
if (!item.invalid) list[count++] = item;
}
list.RemoveRange(count, list.Count - count);
}
void ProcessItem(ref combo item)
{
// do the processing and set item.invalid=true/false
}
In case you are not mutating the item inside the ProcessItem, you can remove the ref modifier, change the return type to bool and use it to control whether the item should be removed from the list or not.
Here is an example of using HashSet. It is very fast.
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var myInts = new HashSet<int>();
for (var i = 0; i < 100000; i++)
myInts.Add(i);
myInts.Remove(62345);
}
}
}

When can IEnumerable not be converted to IList?

I found this code in a project I'm working on:
IEnumerable<int> foo = iEnumerableIntVariable as IList<int> ?? iEnumerableIntVariable.ToList();
I know that as returns null if it can't successfully convert, and that ToList() would then kick in to finish the job, but what are the situations in which that would happen?
Among others, consider this simple case:
public IEnumerable<int> GetListOfNumbers()
{
for (int i = 0; i < 100; i++)
yield return i;
}
This returns a true IEnumerable that wouldn't implement IList as well (MSDN). Clearly, adding/removing from this "collection" doesn't make any sense, nor are elements accessible via index.

Remove everything which is duplicate in a List<List<double[]>>

I hope you can help me out on this one. I have a List < List < double[] > > and I want to remove everything which is duplicate in such list. That is:
1) Within the List < double[] > there are some of the double[] which are duplicate.I want to keep only the non-duplicate doubles[] within the List < double[] >. See lists 1 and 5 in the picture.
2) Within List < List < double[] > > there are some of the List < double[] > which are duplicate. I want to keep only the non-repeated lists. See lists 0 & 2 and lists 1 & 3.
The desired output is designated in the picture:
I have tried the following but it doesn't work.
public static List<List<double[]>> CleanListOfListsOfDoubleArray(List<List<double[]>> input)
{
var output = new List<List<double[]>>();
for (int i = 0; i < input.Count; i++)
{
var temp= input[i].Distinct().ToList();
output.Add(temp);
}
return output.Distinct().ToList();
}
Can you please help me on this?
Your code (excluding the ToList collectors) seems logically equivalent to:
return input.Select(t => t.Distinct()).Distinct();
You're trying to use Distinct on collections. That's reasonable, since you are expecting to get distinct collections.
The problem is that you have left Distinct without logic to compare these collections. Without specifying that logic, Distinct can't compare collections properly (by equality of each individual member).
There is another overload of Distinct that takes an IEqualityComparer<T> as an argument. To use it, you'll have to implement such a comparer first. A reasonable implementation (adapted from Cédric Bignon's answer) could look like this:
public class ArrayComparer<T> : IEqualityComparer<T[]>
{
public bool Equals(T[] x, T[] y)
{
return ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y));
}
public int GetHashCode(T[] obj)
{
return 0;
}
}
public class ListOfArrayComparer<T> : IEqualityComparer<List<T[]>>
{
public bool Equals(List<T[]> x, List<T[]> y)
{
return ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y, new ArrayComparer<T>()));
}
public int GetHashCode(List<T[]> obj)
{
return 0;
}
}
Your code should then look like this:
public static List<List<double[]>> CleanListOfListsOfDoubleArray(List<List<double[]>> input)
{
var output = new List<List<double[]>>();
for (int i = 0; i < input.Count; i++)
{
var temp = input[i].Distinct(new ArrayComparer<double>()).ToList();
output.Add(temp);
}
return output.Distinct(new ListOfArrayComparer<double>()).ToList();
}
Or even just:
public static List<List<double[]>> CleanListOfListsOfDoubleArray(List<List<double[]>> input)
{
var output = input.Select(t => t.Distinct(new ArrayComparer<double>()).ToList()).ToList();
return output.Distinct(new ListOfArrayComparer<double>()).ToList();
}
Keep in mind that this would be a lot less complicated if you used more specific types for describing your problem.
If, for example, instead of double[], you used a more specific pair type (like Tuple<double, double>), you would only need to implement one comparer (the first Distinct call could be left with its default behavior, if I remember correctly).
If, instead of the List<double> you had a specialized PairCollection that implements its own equality method, you wouldn't need the second equality comparer either (your original code would work as it already is, most probably).
So, to avoid problems like this in the future, try to declare specialized types for your problem (instead of relying on the generic lists and arrays and nesting them like here).

JAVA to C# conversion - PriorityQueue

This question was posted here (https://stackoverflow.com/questions/15881110/java-to-c-sharp-conversion) by a team member but was closed due to the community not having enough information.
Here's my attempt to revive such a question being, How would I go about converting this java extract into C#?
Java Extract:
PriorityQueue<PuzzleNode> openList = new PriorityQueue<PuzzleNode>
(1,
new Comparator<PuzzleNode>(){
public int compare(PuzzleNode a, PuzzleNode b){
if (a.getPathCost() > b.getPathCost())
return 1;
else if (a.getPathCost() < b.getPathCost())
return -1;
else
return 0;
}
}
);
A sortedList has been thought about but to no avail as I'm unsure how to code it.
I've also tried creating a standard list with a method:
List<PuzzleNode> openList = new List<PuzzleNode>();
//Method to sort the list
public int CompareFCost(PuzzleNode a, PuzzleNode b)
{
if (a.getPathCost() > b.getPathCost())
{
return 1;
}
else if (a.getPathCost() > b.getPathCost())
{
return -1;
}
else
return 0;
}//end CompareFCost
and then calling: openList.Sort(CompareFCost); at appropriate locations, however this doesn't work.
What the code is used for?
It orders the objects 'PuzzleNode' depending on a score (pathCost) I have set else where in the program. A while loop then operates and pulls the first object from the list. The list needs to be ordered otherwise an object with a higher pathCost could be chosen and the while loop will run for longer. The objective is to pull the lower pathCost from the list.
I ask for a conversion because it works in Java & the rest of the code has pretty much originated from Java.
Any takers? If you need further info I'm happy to discuss it further.
I suppose you could misappropriate a SortedList something like this:
var openList=new SortedList<PuzzleNode,PuzzleNode>(
//assumes .Net4.5 for Comparer.Create
Comparer<PuzzleNode>.Create((a,b)=>{
if (a.getPathCost() > b.getPathCost())
return 1;
else if (a.getPathCost() < b.getPathCost())
return -1;
else
return 0;
}));
openList.Add(new PuzzleNode());
foreach(var x in openList.Keys)
{
//ordered enumeration
}
var firstItem = openList.Dequeue();
by creating some extension methods to make things a little more queue-like
static class SortedListExtensions
{
public static void Add<T>(this SortedList<T,T> list,T item)
{
list.Add(item,item);
}
public static T Dequeue<T>(this SortedList<T,T> list)
{
var item=list.Keys.First();
list.Remove(item);
return item;
}
//and so on...
}
TBH, I'd probably go for #valverij's answer in the comment to your original question, but if the cost of repeated sorting is prohibitive, this may be what you need.
What the code is used for? It orders the objects 'PuzzleNode'
depending on a score (pathCost) I have set else where in the program.
A while loop then operates and pulls the first object from the list.
The list needs to be ordered otherwise an object with a higher
pathCost could be chosen and the while loop will run for longer. The
objective is to pull the lower pathCost from the list.
1: There's LinQ for that. You don't usually do any of these things in C#, because LinQ does it for you.
It orders the objects 'PuzzleNode' depending on a score (pathCost)
That's Achieved with LinQ's Enumerable.OrderBy() Extension:
//Assuming PathCost is a property of a primitive type (int, double, string, etc)
var orderedlist = list.OrderBy(x => x.PathCost);
The objective is to pull the lower pathCost from the list.
That's achieved using LinQ's Enumerable.Min() or Enumerable.Max() extensions.
//Same assumption as above.
var puzzlewithlowestpath = list.Min(x => x.PathCost);
here goes my rant about java being incomplete compared to C# because it lacks something like LinQ, but I will not do any more ranting in StackOverflow by now.
Another thing I wanted to mention is that if you are coding in C#, you'd better use C# Naming Conventions, where Properties are ProperCased:
public int PathCost {get;set;}
//or double or whatever
instead of:
public int getPathCost()
public int setPathCost()

Categories

Resources