TASK: Create a method that receives as argument a list of any type that can be compared and an element of the given type. The method should return the count of elements that are greater than the value of the given element. Modify your Box class to support comparing by value of the data stored.
On the first line you will receive n - the number of elements to add to the list. On the next n lines, you will receive the actual elements. On the last line you will get the value of the element to which you need to compare every element in the list.
INPUT:
3
aa
aaa
bb
(givenElement is "aa")
OUTPUT:
2
Here is my code, i dunno how to compare them ...
public class Box<T> : IComparable<Box<T>>
{
private T value;
public Box(T value)
{
this.value = value;
}
public T Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public int CompareTo(Box<T> other)
{
// ???
}
public override string ToString()
{
return string.Format($"{value.GetType().FullName}: {value}");
}
}
static void Main()
{
int n = int.Parse(Console.ReadLine());
List<Box<string>> boxList = new List<Box<string>>();
for (int i = 0; i < n; i++)
{
string input = Console.ReadLine();
var box = new Box<string>(input);
boxList.Add(box);
}
string inp = Console.ReadLine();
var elementComparer = new Box<string>(inp);
GenericCountMethod(boxList, elementComparer);
}
public static int GenericCountMethod<T>(List<T> boxList, T str)
where T : IComparable<T>
{
int count = 0;
foreach (var item in boxList)
{
var x = item.CompareTo(str);
// ??
}
return count;
}
You could apply a constraint to a class
public class Box<T> : IComparable<Box<T>> where T: IComparable<T>
and then use CompareTo implementation of value:
public int CompareTo(Box<T> other)
{
return value.CompareTo(other.Value);
}
Related
I've got a List<Card>, and I want to sort these cards
So, I'm looking for a method to sort them with different criterias, like their ID, their Name ...
public class Card : IComparer
{
public string ID;
public string Name;
public int CompareId(object firstCard, object secondCard)
{
Card c1 = (Card)firstCard;
Card c2 = (Card)secondCard;
return c1.Id.CompareTo(c2.Id);
}
}
But then, visual studio sent me an error :
'Card' does not implement interface member 'IComparer<Card>.Compare(Card, Card)'
You, probably, want to have your class Comparable not a Comparator
public class Card : IComparable<Card>
{
public string ID;
public string Name;
public int CompareTo(Card other)
{
if (null == other)
return 1;
// string.Compare is safe when Id is null
return string.Compare(this.Id, other.Id);
}
}
then
List<Card> myList = ...
myList.Sort();
Edit: If you want to have several criteria to choose from, you have to implement several Comparers as separated classes, e.g.
public sealed class CardByIdComparer : IComparer<Card>
{
public int Compare(Card x, Card y)
{
if (object.ReferenceEquals(x, y))
return 0;
else if (null == x)
return -1;
else if (null == y)
return 1;
else
return string.Compare(x.Id, y.Id);
}
}
and when sorting provide the required:
List<Card> myList = ...
myList.Sort(new CardByIdComparer());
Edit 2: (inspired by spender's library). If you want to combine several comparers into one (i.e. use comparer1, on tie - comparer2 etc.)
public sealed class ComparerCombined<T> : IComparer<T> {
private IComparer<T>[] m_Comparers;
public ComparerCombined(params IComparer<T>[] comparers) {
if (null == comparers)
throw new ArgumentNullException(nameof(comparers));
m_Comparers = comparers
.Select(item => item == null ? Comparer<T>.Default : item)
.Where(item => item != null)
.Distinct()
.ToArray();
}
public int Compare(T x, T y) {
if (object.ReferenceEquals(x, y))
return 0;
else if (null == x)
return -1;
else if (null == y)
return 1;
foreach (var comparer in m_Comparers) {
int result = comparer.Compare(x, y);
if (result != 0)
return result;
}
return 0;
}
}
usage:
myList.Sort(new ComparerCombined(
new CardByIdComparer(), // Sort By Id
new CardByNameComparer() // On tie (equal Id's) sort by name
));
The easiest way You can use Linq:
List<Card> objSortedList = objListObject.OrderBy(o=>o.ID).ToList();
or
List<Card> objSortedList = objListObject.OrderByDescending(o=>o.ID).ToList();
Good examples for demonstrate the concept of
List<T>.Sort(IComparer <T>) method check the link please.
IComparer<T> in this example compare method used for strings IComparer<T>
but you can use this for ID(int) too.
using System;
using System.Collections.Generic;
class GFG : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null || y == null)
{
return 0;
}
// "CompareTo()" method
return x.CompareTo(y);
}
}
public class geek
{
public static void Main()
{
List<string> list1 = new List<string>();
// list elements
list1.Add("C++");
list1.Add("Java");
list1.Add("C");
list1.Add("Python");
list1.Add("HTML");
list1.Add("CSS");
list1.Add("Scala");
list1.Add("Ruby");
list1.Add("Perl");
int range = 4;
GFG gg = new GFG();
Console.WriteLine("\nSort a range with comparer:");
// sort the list within a
// range of index 1 to 4
// where range = 4
list1.Sort(1, range, gg);
Console.WriteLine("\nBinarySearch and Insert Dart");
// Binary Search and storing
// index value to "index"
int index = list1.BinarySearch(0, range,
"Dart", gg);
if (index < 0)
{
list1.Insert(~index, "Dart");
range++;
}
}
}
You need to implement IComparer
public int Compare(Card card1, Card card2)
{
if (card1.ID > card2.ID)
return 1; //move card1 up
if (card2.ID < card1.ID)
return -1; //move card2 up
return 0; //do nothing
}
I have a list and in the list there are multiple entries. If the list contains an entry that is duplicated then I want to only keep one of the duplicates.
I've tried many things, the list.Distinct().ToList() and this does not remove the duplicate entry, I do not want to override the classes Equals method, so is there a way outside of that.
I've also done this method which seems to again, not remove the duplicate entry as it does not consider object a == object b.
private void removeDupes(List<Bookings> list)
{
int duplicates = 0;
int previousIndex = 0;
for (int i = 0; i < list.Count; i++)
{
bool duplicateFound = false;
for (int x = 0; x < i; x++)
{
if (list[i] == list[x])
{
duplicateFound = true;
duplicates++;
break;
}
}
if (duplicateFound == false)
{
list[previousIndex] = list[i];
previousIndex++;
}
}
}
There is another overload of the Distinct LINQ extension method that also takes an IEqualityComparer as an argument (see this link). So you'd need to create a class that implements IEqualityComparer<Bookings> and supply an instance of it to the Distinct-method. This way, you do not need to override the Equals method of the type.
The rules on whether two objects are equal to one another are implemented in the EqualityComparer.
As an alternative, you can use a HashSet and supply the EqualityComparer in the constructor.
A possible solution for your problem in order of Markus answer might look like this:
public class Booking
{
public Booking(int id, float amount)
{
BookingId = id;
BookingAmount = amount;
}
public int BookingId { get; }
public float BookingAmount { get; }
}
public class BookingComparer : IEqualityComparer<Booking>
{
public bool Equals(Booking x, Booking y)
{
return (x.BookingAmount == y.BookingAmount) && (x.BookingId == y.BookingId);
}
public int GetHashCode(Booking obj)
{
return obj.BookingId.GetHashCode()*17 + obj.BookingAmount.GetHashCode()*17;
}
}
internal class Program
{
private static void Main(string[] args)
{
var booking1 = new Booking(1, 12);
var booking2 = new Booking(1, 12);
var bookings = new List<Booking>();
bookings.Add(booking1);
bookings.Add(booking2);
var result = bookings.Distinct(new BookingComparer()).ToList();
}
}
I have a List<Unit> where Unit contains Name and Value. In this object I store information about apparel sizes Name contains size names (S,M,L,XL..) and Value contains the quantity of that size.
This unit list is contained from a database, but the list comes in random order, so in the liste it might be like this:
Unit(M,3)
Unit(S,1)
Unit(XXL,2)
Unit(L,2)
I would like to sort the list so that it become more like this:
Unit(S,1)
Unit(M,3)
Unit(L,2)
Unit(XXLL,2)
I cant order on the string ASCE or DESC since it M comes before S and so on.
Then I thought I might create an reference Array with the correct order (XXS,XS,S,M,L,XL,XXL,XXXL), but how can I sort my list according to the reference.
Or are there other clever ways of doing this?
Update
Thanks for all good answers, I landed on the Enum solution, and it finally looks like this:
public class Unit
{
public Unit()
{
}
public Unit(string name, int value)
{
Value = value;
SizeCode = AssignSizeCode(name);
}
public SizeCode SizeCode { get; set; }
public int Value { get; set; }
private SizeCode AssignSizeCode(string name)
{
switch (name)
{
case "XXS":
return SizeCode.XXS;
case "XS":
return SizeCode.XS;
case "S":
return SizeCode.S;
case "M":
return SizeCode.M;
case "L":
return SizeCode.L;
case "XL":
return SizeCode.XL;
case "XXL":
return SizeCode.XXL;
case "XXXL":
return SizeCode.XXXL;
default:
return SizeCode.Unknown;
}
}
}
public enum SizeCode
{
XXS = 1,
XS = 2,
S = 3,
M = 4,
L = 5,
XL = 6,
XXL = 7,
XXXL = 8,
Unknown = 9
}
And I sort it like this:
units = units.OrderBy(x => (int)x.SizeCode).ToList();
Any comments, or things I can improve?
How about using a enum
public enum Size
{
Small = 1,
Medium = 2,
// etc
}
Then you can convert the enum value in Unit class to int and sort by the integer value.
Ok, I consider you should have OrderIndex column in your database and sort by that column.
the dirty way is to have your own class with interface : IComparer or do the same as delegate for sorting.
Check ICompararer in MSDN: http://msdn.microsoft.com/en-us/library/system.collections.icomparer.aspx
You can do exactly what MSDN suggest here:
// First, declare a few classes that implement the IComparer interface.
public class CompareShirtSize : IComparer<string>
{
// Because the class implements IComparer, it must define a
// Compare method. The method returns a signed integer that indicates
// whether s1 > s2 (return is greater than 0), s1 < s2 (return is negative),
// or s1 equals s2 (return value is 0). This Compare method compares strings.
public int Compare(string size1, string size2)
{
// Do size comarison here
return ConvertSizeToInt(size1) - ConvertSizeToInt(size2);
}
private int ConvertSizeToInt(string size)
{
switch (size)
{
case "XXS":
return 1;
case "XS":
return 2;
case "S":
return 3;
case "M":
return 4;
case "L":
return 5;
default:
// some error handling
}
}
// The following method tests the Compare methods defined in the previous classes.
public static void OrderByIComparer()
{
List<Unit> units;
// Sort the elements of the array alphabetically.
var sortedList = units.OrderBy(unit => unit.Size, new CompareShirtSize ());
}
You could add a Size property of type int in your class Unit. Then sort your list using this Size property.
public class Unit1
{
public Unit1(string name)
{
this.Name = name;
switch (this.Name)
{
case "XXS":
this.Size = 1;
break;
case "XS":
this.Size = 2;
break;
case "S":
this.Size = 3;
break;
case "M":
this.Size = 4;
break;
case "L":
this.Size = 5;
break;
}
}
public string Name { get; set; }
public int Size { get; private set; }
public int Value { get; set; }
}
private static void Main(string[] args)
{
List<Unit1> list1 = new List<Unit1>();
list1.Add(new Unit1("XS") { Value = 1 });
list1.Add(new Unit1("M") { Value = 1 });
list1.Add(new Unit1("S") { Value = 1 });
list1.Add(new Unit1("L") { Value = 1 });
var sortedList = list1.OrderBy(z => z.Size).ToList();
}
You simply need to use a Comparison Delegate. Firstly, make a function that just assigns a number to every size and then use that for comparison:
(I am not sure whether your sizes are stored as a String as an enum; but I would recommend storing them as an enum with the ordinal numbers in order of the sizes, increasing or decreasing. This will help make your comparison delegate faster and simpler).
public class ShirtSizeCompare {
private static int getIndex(Unit x) {
if(x == Null) { return -1; }
if(x.size == "S") {
return 0;
} else if(x.size == "M") {
return 1;
}
///...
}
private static int CompareShirts(Unit x, Unit y) {
int _x = getIndex(x);
int _y = getIndex(y);
if(_x < _y) {
return -1;
} else if(_x == _y) {
return 0;
} else {
return 1;
}
}
}
Then, simply use the Comparison delegate to sort the list:
List<Unit> unitList;
unitList.sort(CompareShirts);
The comparison delegate basically takes as input two variables x and y and returns:
<0 (if x < y)
>0 (if x > y)
0 (if x == y)
Check this page for more information: http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx
How to create dynamic incrementing variable using "for" loop in C#? like this:
track_1, track_2, track_3, track_4. so on.
You can't create dynamically-named variables. All you can do - it to create some collection or array, and operate with it.
I think the best class for you is generic List<>:
List<String> listWithDynamic = new List<String>();
for (int i = 1; i < limit; i +=1)
{
listWithDynamic.Add(string.Format("track_{0}", i));
...
}
Assuming you want strings:
for (int i = 1; i < limit; i +=1)
{
string track = string.Format("track_{0}", i);
...
}
But when you already have variables called track_1, track_2, track_3, track_4 you will need an array or List:
var tracks = new TrackType[] { track_1, track_2, track_3, track_4 } ;
for (int i = 0; i < tracks.length; i++)
{
var track = tracks[i]; // tracks[0] == track_1
...
}
Obvious Solution
for (var i = 0; i < 10; i++)
{
var track = string.Format("track_{0}", i);
}
Linq-Based Solution
foreach (var track in Enumerable.Range(0, 100).Select(x => string.Format("track_{0}", x)))
{
}
Operator-Based Solution This is somewhat hacky, but fun none-the-less.
for (var i = new Frob(0, "track_{0}"); i < 100; i++)
{
Console.WriteLine(i.ValueDescription);
}
struct Frob
{
public int Value { get; private set; }
public string ValueDescription { get; private set; }
private string _format;
public Frob(int value, string format)
: this()
{
Value = value;
ValueDescription = string.Format(format, value);
_format = format;
}
public static Frob operator ++(Frob value)
{
return new Frob(value.Value + 1, value._format);
}
public static Frob operator --(Frob value)
{
return new Frob(value.Value - 1, value._format);
}
public static implicit operator int(Frob value)
{
return value.Value;
}
public static implicit operator string(Frob value)
{
return value.ValueDescription;
}
public override bool Equals(object obj)
{
if (obj is Frob)
{
return ((Frob)obj).Value == Value;
}
else if (obj is string)
{
return ((string)obj) == ValueDescription;
}
else if (obj is int)
{
return ((int)obj) == Value;
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return Value;
}
public override string ToString()
{
return ValueDescription;
}
}
don't know if I get your question, but I will try:
for(var i = 1; i < yourExclusiveUpperbound; i++)
{
var track = String.Format("$track_{0}", i);
// use track
}
or with some LINQ-Magic:
foreach(var track in Enumerate.Range(1, count)
.Select(i => String.Format("$track_{0}", i)))
{
// use track
}
Do as follow:
for (int i = 0; i < lenght; i ++)
{
any work do in loop
}
No, we can't create dynamically named variables in a loop. But, there are other elegant ways to address the problem instead of creating dynamically named variables.
One could be, create an array or list before the loop and store values in array / list items in the loop. You can access the array / list later anywhere in your code. If you know which variable you want to use (track_1, track_2, ...), you can simply access it from the array / list (tracks[1], tracks[2], ...).
List<String> tracks = new List<String>();
for (int i = 1; i < limit; i++)
{
Track track = new Track();
tracks.Add(track);
...
}
I wrote a struct
public struct SeasonEpisodeNr
{
public int seasonNr;
public int episodeNr;
}
During my program I will add those structs to an ArrayList. How can I sort them? I tried the IComparer but unfortunately I was not able to understand how it works.
I didn't test this but it's something like...
public struct SeasonEpisodeNr: IComparable
{
public int seasonNr;
public int episodeNr;
public int CompareTo(Object Item)
{
SeasonEpisodeNr that = (SeasonEpisodeNr) Item;
if (this.seasonNr > that.seasonNr)
return -1;
if (this.seasonNr < that.seasonNr)
return 1;
if (this.episodeNr > that.episodeNr)
return -1;
if (this.episodeNr < that.episodeNr)
return 1;
return 0;
}
public struct SeasonEpisodeNr
{
public SeasonEpisodeNr(int seasonNr, int episodeNr)
{
this.seasonNr = seasonNr;
this.episodeNr = episodeNr;
}
public int seasonNr; public int episodeNr;
}
static void Main(string[] args)
{
List<SeasonEpisodeNr> list = new List<SeasonEpisodeNr>();
list.Add(new SeasonEpisodeNr(1, 2));
list.Add(new SeasonEpisodeNr(1, 1));
list.Sort((a, b) =>
{
//implement comparison, e.g. compare season first and if equal compare the epizods
int res = a.seasonNr.CompareTo(b.seasonNr);
return res != 0 ? res : a.episodeNr.CompareTo(b.episodeNr);
});
}
Check out the example in this link
http://msdn.microsoft.com/en-us/library/8ehhxeaf.aspx
The basic idea is to
Create a IComparer implementation that returns -1 (less than), 0 (equals) or 1 (greater than) based on your custom comparison criteria.
Next pass an instance of this class to the Sort method of your List()
Another (a bit long-drawn) example that illustrates this