How to sort list of class object - c#

I have list of model class object. class scoreboard which have total score as one property.
Scoreboard scoreboard = new Scoreboard();
I am sorting list like this
data= data.OrderByDescending(x => x.totalScore).ToList()
but wont work.
please what should I do the list is of object of class.

If I understood your sorting issue correctly, this might help
List<Class1> Scores = new List<Class1>();
Scores.Add(new Class1 { Score = 1, TotalScore = 2, User = "A" });
Scores.Add(new Class1 { Score = 1, TotalScore = 5, User = "B" });
Scores.Add(new Class1 { Score = 1, TotalScore = 3, User = "C" });
Scores = Scores.OrderByDescending(x => x.TotalScore).ToList();
This will sort it by total score.

You can sort your score if you have the data like below as one property,
List<int> scoreData = new List<int>();
scoreData.Add(300);
scoreData.Add(201);
scoreData.Add(400);
Then to sort,
var sortedData = data.Sort();

Related

How can i get specific item in a list using LINQ

So I am learning the basics of LINQ and I´m haveing a little trouble.
How can I get the interval under entry name and exit name?? I'm having a hard time to solve this.
this is the code
List<list> list = new List<list>();
station1 = new list()
{
no = 1,
interval = 0,
name = "name1",
};
station2 = new list()
{
no = 2,
interval = 1,
name = "name2",
};
station3 = new list()
{
no= 3,
interval = 2,
name = "name3",
};
station4 = new list()
{
no = 4,
interval = 1,
name = "name4",
};
station5 = new list()
{
no = 5,
interval = 1,
name = "name5",
};
for example I enter the entry station and exit station (name1, name5)
I want to add those interval inside the station under name1 and name5.
so the process will be
output = name2.interval = 1 + name3.interval = 2 + name4.interval = 1 ;
total interval = 4
What I tried is, which is wrong and I am stuck:
interval = list.GetRange(entry, exit);
This only gives me the interval of entry so I need to add a filter. Been trying this and that with no luck. If anyone could give me more hints or be of some assistance would be greatly appreciated
I suggest using Skip and Take:
int total = list
.OrderBy(item => item.no) // if stations are not ordered
.SkipWhile(item => item.name != "name1") // skip before 1st station
.Skip(1) // skip 1st station
.TakeWhile(item => item.name != "name5") // take up to the last station
.Sum(item => item.interval); // sum intervals
First, you'd have to get the no of stations with "name1" and "name5". After that, you can get the total with a LINQ query like this:
var no1 = list.First(x => x.name == "name1").no;
var no5 = list.First(x => x.name == "name5").no;
var total = list
.Where(x => x.no > no1 && x.no < no5)
.Sum(x => x.interval);
This sample assumes that the stations exist. After getting the no of the stations it filters the list for items with a no between the stations and afterwards builds the sum of the interval field for these items.
In addition, it iterates the list several times. If you want to find the stations by name more efficiently, you could change your list to a Dictionary<string, list> where name is the key and the item is the value. Then you can simply look the items up by name and iterate the list only once. In memory with a limited number of items, the difference will not be too big between the list and the dictionary.

Order a List a specific way

I have a problem. I have a list with 4 coins and 4 values. Now the List is sorted by name like this:
1. BTC---Value
2. ETH---Value
3. LTC---Value
4. USDT---Value
But now I want to get a List with only 2 coins left:
The last coin needs to be USDT and the first Coin is the coin with the highest value. So for example if all the coins have value 3 and BTC has value 4, then I want a List like this:
1. BTC---Value
2. USDT---Value
How can I do that, because I know how to sort by value, but not with all my preferences....
Can someone help me?
DETAILS
Even if USDT has the highest value, I want that coin at the last place. If you add another coin, it needs to just look at the highest value again (except for USDT) and place that coin at the top with USDT on second place!
Updated code based on comment by DubDub.
var intermediate = list.OrderBy(x=> x.Name=="USDT").ThenByDescending(x=>x.Value);
var result = new []{intermediate.First(),intermediate.Last()};
Example,
Scenario 1 : When there are more than 2 items
var list = new List<Coin>
{
new Coin{Name="USDT", Value = 29},
new Coin{Name="ETH", Value = 13},
new Coin{Name="LTC", Value = 21},
new Coin{Name="BTC", Value = 3},
};
Output
Scenario 2 : When there are only two items
var list = new List<Coin>
{
new Coin{Name="USDT", Value = 29},
new Coin{Name="LTC", Value = 21},
};
You could do it with Linq. This wouldn't modify the list; it would create a new enumerable sorted by your criteria.
var sortedCoins = coins.OrderBy(c => c.Name == "USDT")
.ThenByDescending(c => c.Value);
Using the following stolen class from a previous answer that is now gone so I'm not sure who to give credit to, but you should be able to do the following.
Coin class
public class Coin
{
public string Name { get; set; }
public double Value { get; set; }
}
Actual code to handle list
List<Coin> list = new List<Coin>
{
new Coin{Name="USDT", Value = 29},
new Coin{Name="ETH", Value = 13},
new Coin{Name="LTC", Value = 21},
new Coin{Name="BTC", Value = 3},
};
// Take out USDT coin
Coin USDTcoin = list.Find(coin => coin.Name == "USDT");
list.RemoveAt(list.FindIndex(coin => coin.Name == "USDT"));
// Order list
list = list.OrderByDescending(coin => coin.Value).ToList();
// Make new list
list = new List<Coin>
{
list[0],
USDTcoin
};
This way:
class Program
{
static void Main(string[] args)
{
List<Coin> coins = new List<Coin>()
{
new Coin ("BTC", 1),
new Coin ("ETH", 2),
new Coin ("LTC", 3),
new Coin ("USDT", 4),
};
Coin usdt = coins.First(x => x.Name == "USDT");
coins.Remove(usdt);
coins = new List<Coin>() { coins.OrderByDescending(x => x.Value).First(), usdt };
}
}
public class Coin
{
public string Name { get; set; }
public double Value { get; set; }
public Coin(string name, double value)
{
Name = name;
Value = value;
}
}

Order by second Dimesion of String Array in C#

We Have 2 dimensional string array like
"0" => {"John","23"},
"1" => {"Doe","12"},
"2" => {"Maria","41"},
.......
We want to sort this array like
"0" => {"Maria","41"},
"1" => {"John","23"},
"2" => {"Doe","12"},
.......
Our Array Code String[,] kelimedeger = new String[20, 2];
We want order by kelimedeger[i,1]
Regarding Sorting
One of the problems I see here is that your second "string" is actually not a string, but rather a number. As such, you actually have a person with a name and an age.
Why does this matter?
Sorting depends on the types of data. Strings are sorted alphabetically, while numbers are sorted numerically.
Consider the following list:
1, 2, 17, 11, 100, 20, 34
This can be sorted in multiple ways
Numerical Alphabetical
--------- ------------
1 1
2 100
11 11
17 17
20 2
34 20
100 34
Given that you will most likely want to sort numerically, you need to store your data as int, not as string.
How to store the data?
This depends on your use-case. If names are guaranteed to be unique, then you could use a Dictionary<string,int>. Otherwise, I advise you to create a class Person and use a ICollection<Person> to store them.
As Dictionary<string, int>
This approach is useful if names are guaranteed to be unique in your domain. Further, it only uses built-in types.
namespace DictionaryTest
{
public class Program
{
public static void Main(string[] args)
{
//Create a dictionary to store people
Dictionary<string, int> people = new Dictionary<string, int>();
//Add some people. Note that this is type-safe
people.Add("John", 23);
people.Add("Doe", 12);
people.Add("Maria", 41);
//people.Add("John", 55); // <-- This will fail because there is already a John
//Create queries to ensure correct sorting
var peopleByName = from p in people
orderby p.Key //Our name is the key, the age is the value
select new {Name = p.Key, Age = p.Value};
var peopleByAge = from p in people
orderby p.Value
select new {Name = p.Key, Age = p.Value};
var peopleByAgeDescending = from p in people
orderby p.Value descending
select new {Name = p.Key, Age = p.Value};
//Execute the query and print results
foreach(var person in peopleByAge)
{
Console.WriteLine("Hello, my name is {0} and I am {1} years old", person.Name, person.Age);
}
}
}
}
Try it online!
As ICollection<Person>
This approach defines a class Person, which only holds a Name and an Age property, but can be extended to contain much more information, methods, etc.
namespace ClassTest
{
public class Program
{
public static void Main(string[] args)
{
//Create a list to store people
ICollection<Person> people = new List<Person>();
//Add some people. Note that this is type-safe
people.Add(new Person(){ Name = "John", Age = 23, FavouriteColour = "Blue" });
people.Add(new Person(){ Name = "Doe", Age = 12});
people.Add(new Person(){ Name = "Maria", Age = 41, FavouriteColour = "Purple" });
people.Add(new Person(){ Name = "John", Age = 55, FavouriteColour = "Gray" }); //<-- You can indeed have two people with the same name
//Create queries to ensure correct sorting
var peopleByName = from p in people
orderby p.Name
select p;
var peopleByAge = from p in people
orderby p.Age
select p;
var peopleByAgeDescending = from p in people
orderby p.Age descending
select p;
//Execute the query and print results
foreach(var person in peopleByAge)
{
Console.WriteLine("Hello, my name is {0} and I am {1} years old.", person.Name, person.Age);
if(person.FavouriteColour != null)
{
Console.WriteLine("My favourite colour is {0}.", person.FavouriteColour);
}
else
{
Console.WriteLine("I have no favourite colour.");
}
Console.WriteLine(); //Add a new line for better readability
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string FavouriteColour { get; set; }
}
}
Try it online!
I personally like the second approach better, as it is more extendable and does not have a requirement for uniqueness of the name. It allows you to extend the Person class as much as you like, and gives you many more options for sorting.
To sort a two-dimensional array you need to convert each row to a one-dimensional array and save it in a List or something similar. Then you can sort the list by the column. After sorting you need to convert the list back to a two-dimensional array.
Here is a method you could use for sorting:
public static T[,] Sort2DArray<T>(T[,] array, int column, bool ascending = true)
{
int i = 0;
List<T[]> items = new List<T[]>();
int columns = array.GetLength(1);
int rows = array.GetLength(0);
T[] obj = new T[columns];
foreach (var item in array)
{
obj[i % columns] = item;
if ((i + 1) % 2 == 0)
{
items.Add(obj);
obj = new T[columns];
}
i++;
}
var ordered = ascending ? items.OrderBy(a => a[column]) : items.OrderByDescending(a => a[column]);
T[,] result = new T[rows, columns];
for (int r = 0; r < rows; r++)
{
var row = ordered.ElementAt(r);
for (int c = 0; c < columns; c++)
{
result[r, c] = row[c];
}
}
return result;
}
Your code would look like this:
string[,] array =
{
{"John", "23" },
{"Doe", "12" },
{"Maria", "41" },
};
string[,] ordered = Sort2DArray(array, 1);//Sort by column 1 / Age
Converting a two-dimensional array to one- dimensional array and back is not the best routine to sort your values. The best way is to create a class to store your data, just as David Stockinger and Tim Schmelter said.

Linq Select that will generate tied scores for similar values

I'm trying to generate a simple league table with positional numbers based on scores.
e.g. Given the following
List<Player> players = new List<Player>() {
new Player { Name = "John", Score = 2 },
new Player { Name = "Mary", Score = 1 },
new Player { Name = "Bob", Score = 2 },
new Player { Name = "Alice", Score = 3 },
};
var results = players
.OrderByDescending(o => o.Score)
.Select((v,i) => new { Name = v.Name, Score = v.Score, Position = i+1} );
The Results would be.
Name Score Pos
Alice 3 1
John 2 2
Bob 2 3
Mary 1 4
Instead, I'd like the result to be
Name Score Pos
Alice 3 1
John 2 2
Bob 2 2 <---- this guy is tied for second
Mary 1 4 <---- this one still comes fourth
Is there anyway to access the previous or next elements during a Linq Select so you know whether to increment or decrement the index value ?
Would something like this do the trick for you?
.Select((v,i) => new { Name = v.Name,
Score = v.Score,
Position =
players.Count(p => p.Score > v.Score) + 1
}
);
it but sounds like you want to do a group by/selectmany
var results = players
.OrderByDescending(o => o.Score)
.GroupBy(o => o.Score)
.SelectMany((l, i) => l.Select(v => new { Name = v.Name, Score = v.Score, Position = i + 1 }));
You almost have the solution with the indexed select statement, sort the dataset first though.
Edit: Made a small edit because I had the sorter in the wrong order, i.e. it sorted in the ascending order.
List<Player> players = new List<Player>() {
new Player { Name = "John", Score = 2 },
new Player { Name = "Mary", Score = 1 },
new Player { Name = "Bob", Score = 2 },
new Player { Name = "Alice", Score = 3 },
};
players.Sort(delegate(Player x, Player y)
{
return y.Score.CompareTo(x.Score);
});
var results = players
.Select((v,i) => new {
Name = v.Name,
Score = v.Score,
Position = i+1,
TiedWithPrevious = i > 0 && players[i-1].Score == v.Score,
TiedWithNext = i < players.Count-1 && players[i+1].Score == v.Score } );

How to make an array like this

List<Customer> c= new List<Customer>()
{
new Customer{Id = 1, Name = "Bruce"},
new Customer{Id = 2, Name = "John"}
};
I just know
c.ForEach(o => str += o.Id.ToString() + ",");
Any ways to make it simple?
I just wanna get Id out and make Ids array int[] Ids = new {Id = 1, Id = 2}
If you want to create an array with all those ids then you can use Select and ToArray methods :
int[] ids = c.Select(i => i.Id).ToArray();

Categories

Resources