How can I sort a List by order of case e.g.
smtp:user#domain.com
smtp:user#otherdomain.com
SMTP:user#anotherdomain.com
I would like to sort so that the upper case record is first in the list e.g SMTP:user#anotherdomain.com.
You can use StringComparer.Ordinal to get a case sensitive sorting:
List<string> l = new List<string>();
l.Add("smtp:a");
l.Add("smtp:c");
l.Add("SMTP:b");
l.Sort(StringComparer.Ordinal);
I was writing another example while t4rzsan has answered =) I prefer t4rzsan´s answer... anyway, this is the answer I was writing.
//Like ob says, you could create your custom string comparer
public class MyStringComparer : IComparer<string>
{
public int Compare(string x, string y)
{
// Return -1 if string x should be before string y
// Return 1 if string x should be after string y
// Return 0 if string x is the same string as y
}
}
Example of using your own string comparer:
public class Program
{
static void Main(string[] args)
{
List<string> MyList = new List<string>();
MyList.Add("smtp:user#domain.com");
MyList.Add("smtp:user#otherdomain.com");
MyList.Add("SMTP:user#anotherdomain.com");
MyList.Sort(new MyStringComparer());
foreach (string s in MyList)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
}
Most language libraries have a built in sort function with a way to specify the compare function. You can customize the compare function to sort based on any criteria you want.
In your case the default sort function will probably work.
you need to create a custom comparer class that implements IComparer
Related
I'm desperately trying to delete all the items with a list of the same value inside.
Here's the code:
private void Button_deleteDouble_MouseDown(object sender, EventArgs e)
{
boardGenerate.Add(new BoardInformation(146, new List<string> { "test" }));
boardGenerate.Add(new BoardInformation(545, new List<string> { "test" }));
boardGenerate = boardGenerate.DistinctBy(x => x.positionQueen).ToList();
}
Normally, since the two lists inside the object are the same, the .DistinctBy() command should remove one of the two objects.
But no, my object list still has the same two objects with the same list
.positionQueen is the name of the variable containing the list
Could somebody help me?
Edit :
The DistinctBy() method comes from MoreLinq.
And this is my BoardInformation class:
public class BoardInformation
{
public BoardInformation(int nbQueen, List<string> positionQueen)
{
this.nbQueen = nbQueen;
this.positionQueen = positionQueen;
}
public int nbQueen { get; set; }
public List<string> positionQueen { get; set; }
}
Set-based operations like Distinct and DistinctBy need a way of determining whether two values are the same. You're using DistinctBy, so you're already asking MoreLINQ to compare the "inner lists" for equality - but you're not saying how to do that.
List<T> doesn't override Equals or GetHashCode, which means it inherits the reference equality behaviour from System.Object. In other words, if you create two separate List<T> objects, they won't compare as equal, even if they have the same content. For example:
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
Console.WriteLine(list1.Equals(list2)); // False
You need to tell DistinctBy how you want to compare the two lists, using an IEqualityComparer<T> - where T in this case is List<string> (because that's the type of BoardInformation.positionQueen.
Here's an example of a generic ListEqualityComparer you could use:
using System;
using System.Collections.Generic;
using System.Linq;
public sealed class ListEqualityComparer<T> : IEqualityComparer<List<T>>
{
private readonly IEqualityComparer<T> elementComparer;
public ListEqualityComparer(IEqualityComparer<T> elementComparer) =>
this.elementComparer = elementComparer;
public ListEqualityComparer() : this(EqualityComparer<T>.Default)
{
}
public bool Equals(List<T> x, List<T> y) =>
ReferenceEquals(x, y) ? true
: x is null || y is null ? false
// Delegate to LINQ's SequenceEqual method
: x.SequenceEqual(y, elementComparer);
public int GetHashCode(List<T> obj)
{
if (obj is null)
{
return 0;
}
// Just a very simple hash implementation
int hash = 23;
foreach (var item in obj)
{
hash = hash * 31 +
(item is null ? 0
: elementComparer.GetHashCode(item));
}
return hash;
}
}
You'd then pass that to DistinctBy, like this:
// We're fine to use the default *element* comparer (string.Equals etc)
var comparer = new ListEqualityComparer<string>();
boardGenerate = boardGenerate.DistinctBy(x => x.positionQueen, comparer).ToList();
Now DistinctBy will call into the comparer, passing in the lists, and will consider your two BoardInformation objects are equal - so only the first will be yielded by DistinctBy, and you'll end up with a list containing a single item.
It comes down to whether a equality check is using referential equality or value equality...you want value equality based on a specific property and that has to be done by hand.
When there is no IEqualityComparer provided which can used to compare individual objects (which is need by the Distinct call), the system determines the equality from each item's references by using their derived object low level service method call of GetHashCode from each reference; hence a reference difference is done and all your values in the list are unique (not equal) regardless of similar property values.
What you are looking for is to have value equality checked specifically for the nbQueenProperty.
To fully utilize Distinct one must create a IEqualityComparer and modify the GetHashCode. By specifing the hash value which can make objects equal...you can weed out the same positionQueen (or other properties) instances out.
Example
public class MyClass
{
public string Name { get; set; }
public int nbQueen { get; set; }
}
Equality comparer to weed out all nbQueen similarities:
class ContactEmailComparer : IEqualityComparer < MyClass >
{
public bool Equals(MyClass x, MyClass y)
{
return x.nbQueen.Equals(y.nbQueen); // Compares by calling each `GetHashCode`
}
public int GetHashCode(MyClass obj)
{
return obj.nbQueen.GetHashCode(); // Add or remove other properties as needed.
}
}
Test code
var original = new List<MyClass>()
{
new MyClass() { nbQueen = 1, Name="Alpha" },
new MyClass() { nbQueen = 1, Name="Omega" },
new MyClass() { nbQueen = 3, Name="Delta" }
};
IEqualityComparer<MyClass> comparer = new ContactEmailComparer();
var newOne = original.Distinct( comparer ).ToList();
Result of the value of newOne :
To be clear...
... .DistinctBy() command should remove one of the two objects.
Does not remove anything. It returns a reference to a new list that should be distinct via the equality operation. The original list (the reference to it) does not change.
LINQ solution
because you have another List inside your class you can not use District or DistrictBy, alternatively, you can use LINQ to filter the list.
boardGenerate = (from b in boardGenerate
from l in b.positionQueen
group new { l,b } by l into g
select g.First().b
).ToList();
// this returns just first duplicate item like district
I have got a method which returns five arrays of different dimensions:
public static (string[],string[],string[,],string[,],string[,]) deserializeobject(string filename)
{
return (Auftraggeber, Aufstellungsort, Anlagen, Vorgang_rückgemeldet, Vorgang_zukünftig);
}
How do I correctly call this method to further work with the arrays?
I would stronly suggest to create a class for that, in particular as the method is public and thus could be used in multiple contexts. That makes it far easier for users of your API to determine the meaning of every returned member.
Your individual members seem to have a descene tmeaning anyway, so why throw it away and return a collection of namesless paramaters?
class MyObject
{
public string[] Auftraggeber { get; set; }
public string[] Aufstellungsort { get; set; }
public string[] Anlagen { get; set; }
public string[] Vorgang_rückgemeldet { get; set; }
public string[] Vorgang_zukünftig { get; set; }
}
And:
public static MyObject Deserialize(string fileName)
{
return new MyObject { AuftragGeber = ... };
}
Now users of your method can easily determine what the parameters mean:
var o = deserialize(myFile);
DoSomething(o.Aufstellungsort);
which is far easier to read than this:
var o DoSomething(myFile);
DoSomething(o.Item2);
isn´t it? Apart from this it limits typos. In the second case users can easily type Item2 when they actually ment Item1, which may cause headache when debugging. With a descent name for every member those typos are far more unlikely.
First the response to your question:
Given:
public static (string[], string[], string[,], string[,], string[,]) deserializeobject(string filename)
{
// Some value that will be returned... Just doing a test here
return default((string[], string[], string[,], string[,], string[,]));
}
You can:
// Using var
var des1 = deserializeobject("foo.bin");
Console.WriteLine($"Lengths: {des1.Item1.Length}, {des1.Item2.Length}, {des1.Item3.Length}, {des1.Item4.Length}, {des1.Item5.Length}");
// Legal, but too much verbose
(string[], string[], string[,], string[,], string[,]) des2 = deserializeobject("foo.bin");
// Legal too, because in truth the ValueTuple<> struct is used
ValueTuple<string[], string[], string[,], string[,], string[,]> des3 = deserializeobject("foo.bin");
Now, the problem here is that, as I've written in a comment, you need a special type of hate for your coworkers to do this. Why? Because if I ask you, what is Item4, can you give me a response? No :-) Fortunately there are two alternatives: creating a full class/struct to contain the return value or using named tuples. I'm quite against creating a class that will be used only by a single method, so I'll show you the named tuples way.
Using named tuples you can:
public static (string[] Auftraggeber, string[] Aufstellungsort, string[,] Anlagen, string[,] VorgangRückgemeldet, string[,] VorgangZukünftig) deserializeobject2(string filename)
{
return default((string[], string[], string[,], string[,], string[,]));
}
Then you can:
// Using var, with named arguments:
var des4 = deserializeobject2("foo.bin");
Console.WriteLine($"Lengths: {des4.Auftraggeber.Length}, {des4.Aufstellungsort.Length}, {des4.Anlagen.Length}, {des4.VorgangRückgemeldet.Length}, {des4.VorgangZukünftig.Length}");
See? The name of the items (arrays) returned by your method is maintained...
Note that named tuples are a sleight of hand. There are no named tuples underside. There are only ValueTuple<> that are "annotated" with the name of the properties that you want.
This is legal:
ValueTuple<string[], string[], string[,], string[,], string[,]> des5 = des4;
Full example to the question in comment:
public static (string[] Auftraggeber, string[] Aufstellungsort, string[,] Anlagen, string[,] VorgangRückgemeldet, string[,] VorgangZukünftig) deserializeobject2(string filename)
{
// Define/create/fill the arrays
var auftraggeber = new string[10];
var aufstellungsort = new string[10];
var anlagen = new string[10, 10];
var vorgangRückgemeldet = new string[10, 10];
var vorgangZukünftig = new string[10, 10];
// Return the arrays
return (auftraggeber, aufstellungsort, anlagen, vorgangRückgemeldet, vorgangZukünftig);
}
use Tuple<> like below code :
public Tuple<int[], int[]> GetMultipleValue(string name)
{
int[] a = new int[]{1,2,3,4}
int[] b = new int[]{5,6,7,8}
return Tuple.Create(a,b);
}
Hope someone can help.
I have created a variable length array that will accept several name inputs.
I now want to sort the array in alphabetical order and return that to the console screen.
I thought that Array.Sort(names); would do this for me but I am getting an exception thrown. I have been looking at notes, examples and on-line but nothing seems to match what I am doing.
I have done the below so far. I am close to tearing my hair out here!
PS I have been trying to figure this out for hours and I am 30+ years old trying to learn myself, so please don't just say "Do your homework" I have tried to resolve this and can not so I need someone to explain where I am going wrong.
It is a Sunday and I am trying to do extra work and have no notes to cover this exactly
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Student_Array
{
class Program
{
struct Student
{
public string Name;
}
static void Main(string[] args)
{
int numberOfStudents;
Student[] names;
string input;
Console.WriteLine("How many students are there?");
input = Console.ReadLine();
numberOfStudents = int.Parse(input);
names = new Student[numberOfStudents];
for (int i = 0; i < names.Length; i++)
{
Student s;
Console.WriteLine("Please enter student {0}'s name", (i + 1));
s.Name = Console.ReadLine();
names[i] = s;
}
***Array.Sort<Student>(names);***
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine(names[i].Name);
}
}
}
}
This shall do the trick
Array.Sort(names, (x,y) => String.Compare(x.Name, y.Name));
Your issue here might be that you are confusing the notions of students and names. By defining the Student struct, you are creating an entity that can represent more than a mere name. You could, for example, extend it to include Age, Hometown, and so forth. (For this reason, it might be more meaningful to name your array students rather than names.)
struct Student
{
public string Name;
public int Age;
public string Hometown;
}
Given the possibility of multiple fields, the Array.Sort method needs to know what you want to sort your list upon. Do you want students ordered by name, by age, or by hometown?
Per the MSDN documentation on Array.Sort<T>:
Sorts the elements in an entire Array using the IComparable<T> generic interface implementation of each element of the Array.
This means that the type you are attempting to sort – in your case, Student – must implement the IComparable<T> interface, in order for the Array.Sort implementation to know how it should compare two Student instances. If you're convinced that students will always be sorted by name, you could implement it like so:
struct Student : IComparable<Student>
{
public string Name;
public int Age;
public string Hometown;
public int CompareTo(Student other)
{
return String.Compare(this.Name, other.Name);
}
}
Alternatively, you could provide a function that extracts the sort key to the sort method itself. The easiest way of achieving this is through the LINQ OrderBy method:
names = names.OrderBy(s => s.Name).ToArray();
You can either use Sort as is if you extend Student to implement IComparable;
struct Student : IComparable<Student>
{
public string Name;
public int CompareTo(Student other)
{
return String.Compare(Name, other.Name,
StringComparison.CurrentCultureIgnoreCase);
}
}
...or you can pass a compare lambda into Sort...
Array.Sort<Student>(names, (x, y) => String.Compare(x.Name, y.Name,
StringComparison.CurrentCultureIgnoreCase));
...or as a third option just create a new, sorted, array;
var newArray = names.OrderBy(x => x.Name.ToLower()).ToArray();
You can use this as well, instead of using Array.Sort.
names = names.OrderBy(p => p.Name).ToArray();
Create a comparer class
class StudentComparer : IComparer<Student>
{
public int Compare(Student a, Student b)
{
return a.Name.CompareTo(b.Name);
}
}
Sort:
Array.Sort(students,new StudentComparer());
To sort by the name property of your Student objects in your Student array, you can use
Array.Sort(names, (s1, s2) => String.Compare(s1.Name, s2.Name));
which will sort your array in place, or with System.Linq:
names = names.OrderBy(s => s.Name).ToArray();
which can return the sorted IEnumerable as an array (.ToArray()) or a list (.ToList().)
Remember to sort case-insensitive if it matters, as pointed out in another answer, which can be done in String.Compare like so:
String.Compare(s1.Name, s2.Name, StringComparison.CurrentCultureIgnoreCase)
you can find one of the basics algorithms here : Simple bubble sort c#
you have to do some modifications , that example is for int, for string you must compare the names.
you can find better algorithms for sorting. for now bubble sort is ok for you.
I am trying to sort an ArrayList using c#. When the ArrayList contains comparable objects, it is possible to sort with using list.Sort() but I need to sort an ArrayList which contains non-comparable objects. For example, let's say the object is Ring and it has an attribute property Price. Then I need to sort the ArrayList to the price order. If is is possible to select ascending or descending that will more helpful. Thank You!
Blockquote
arrAtdMon = **(ArrayList)**hashTb[unixMon];
if (arrAtdMon != null)
monCount = arrAtdMon.Count;
int[] arrayMax = { monCount, tueCount, wedCount, thuCount, friCount };
int maxValue = arrayMax.Max();
KidAttendance valMon = null;
string monTagName = string.Empty;
Blockquote
above array list is to be sorted it self.
You can do this by implementing IComparer interface:-
public class Ring : IComparer
{
public decimal Price { get; set; }
public int Compare(object x, object y)
{
return ((Ring)x).Price.CompareTo(((Ring)y).Price);
}
}
Working Fiddle.
First, you really should be using the List<T> class, not ArrayList. Doing so wouldn't solve your problem, but it would make the code less fragile and more easy to maintain.
As for the specific question, you want to do something like this…
Assume:
class Ring { public decimal Price { get; set; } }
Then:
ArrayList list = ...; // Initialized as some collection of Ring instances
list.Sort(Comparer.Create((r1, r2) => r1.Price.CompareTo(r2.Price)));
This creates a new Comparer instance using the Comparison<T> of (r1, r2) => r1.Price.CompareTo(r2.Price). That is, for each pair of objects being compared, compare the price of the first with the price of the second.
Assuming that these objects share a base class or an interface with the price property you should be able to do something like this:
// Base class with price property, could also be an shared interface
public abstract class Product
{
public decimal Price{get;set;}
}
public class Ring : Product
{
}
public class Bag : Product
{
}
// Some test data
var myUnsortedArray = new Product[]{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArray.OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArray.OrderByDescending(p => p.Price).ToArray();
UPDATE
I just realised that the question is about ArrayLists and have the changed solution below:
// Some test data
var myUnsortedArrayList = new ArrayList{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArrayList.OfType<Product>().OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArrayList.OfType<Product>().OrderByDescending(p => p.Price).ToArray();
To sort an set of objects, the object needs to be Comparable and you can set up the comparison you'd like in the CompareTo() method:
IComparable information here
Say we have a UI and in this UI we have a dropdown. This dropdown is filled with the translated values of an enum.
Bow, we have the possibility to sort by the int-value of the enum, by the name of the enum, and by the translated name of the enum.
But what if we want a different sorting than the 3 mentioned above. how to handle such a requirement?
Implement your own IComparer:
using System;
using System.Collections.Generic;
namespace test {
class Program {
enum X {
one,
two,
three,
four
}
class XCompare : IComparer<X> {
public int Compare(X x, X y) {
// TBA: your criteria here
return x.ToString().Length - y.ToString().Length;
}
}
static void Main(string[] args) {
List<X> xs = new List<X>((X[])Enum.GetValues(typeof(X)));
xs.Sort(new XCompare());
foreach (X x in xs) {
Console.WriteLine(x);
}
}
}
}
You can use the Linq extension OrderBy, and perform whatever comparison magic you want:
// order by the length of the value
SomeEnum[] values = (SomeEnum[])Enum.GetValues(typeof(SomeEnum));
IEnumerable<SomeEnum> sorted = values.OrderBy(v => v.ToString().Length);
Then wrap the different sorting alternatives into methods, and invoke the right one based on user preferences/input.
IEnumerable<T>.OrderBy(Func<T, TKey>, IComparer<TKey>)
Sort FileSystemRights enum using Linq and bind to WinForms comboBox:
comboBox1.DataSource = ((FileSystemRights[])Enum.GetValues(typeof(FileSystemRights))).
OrderBy(p => p.ToString()).ToArray();
Perhapse you could create an extension method for the Enum class, like this:
... first the declaration...
public enum MyValues { adam, bertil, caesar };
...then in a method...
MyValues values = MyValues.adam;
string[] forDatabinding = values.SpecialSort("someOptions");
...The extension method...
public static class Utils
{
public static string[] SpecialSort(this MyValues theEnum, string someOptions)
{
//sorting code here;
}
}
And you could add different parameters to the extension metod for different sort options etc.