Group by descending average test score? - c#

I need help in LINQ, I need to group a list of students based on the calculated average in a rage
There is a student class :
public class Student
{
public string Name { get; set; } // student name
public int[] Scores { get; set; } // test scores
}
and I have a list of students with the data
List<Student> students = new List<Student>
{
new Student { Name = "Michael", Scores = new int[] { 94, 92, 91, 91 } },
new Student { Name = "Isabelle", Scores = new int[] { 66, 87, 65, 93, 86} },
new Student { Name = "Chastity", Scores = new int[] { 76, 61, 73, 66, 54} },
new Student { Name = "Chaim", Scores = new int[] { 94, 55, 82, 62, 52} },
new Student { Name = "Patience", Scores = new int[] { 91, 79, 58, 63, 55} },
new Student { Name = "Echo", Scores = new int[] { 74, 85, 73, 75, 86} },
new Student { Name = "Pamela", Scores = new int[] { 73, 64, 53, 72, 68} },
new Student { Name = "Anne", Scores = new int[] { 78, 96, 52, 79, 60} },
new Student { Name = "Fuller", Scores = new int[] { 59, 68, 88, 85, 76} },
new Student { Name = "Cameron", Scores = new int[] { 70, 73, 75, 51, 98} },
new Student { Name = "Aurora", Scores = new int[] { 65, 70, 53, 80, 52} },
new Student { Name = "Anthony", Scores = new int[] { 68, 69, 94, 88, 98} },
}
the bracket I need to range is in Test score brackets are in multiples of 10
• 50, 60, 70, 80, 90, 100
The output should look like:

Something like that I suppose ?
Result:
--------------------------
90
Name: Michael
--------------------------
--------------------------
80
Name: Isabelle
Name: Echo
Name: Fuller
Name: Anthony
--------------------------
--------------------------
70
Name: Chastity
Name: Chaim
Name: Patience
Name: Pamela
Name: Anne
Name: Cameron
--------------------------
--------------------------
60
Name: Aurora
--------------------------
Code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
internal static class Program
{
private static void Main()
{
var students = new List<Student>
{
new() {Name = "Michael", Scores = new[] {94, 92, 91, 91}},
new() {Name = "Isabelle", Scores = new[] {66, 87, 65, 93, 86}},
new() {Name = "Chastity", Scores = new[] {76, 61, 73, 66, 54}},
new() {Name = "Chaim", Scores = new[] {94, 55, 82, 62, 52}},
new() {Name = "Patience", Scores = new[] {91, 79, 58, 63, 55}},
new() {Name = "Echo", Scores = new[] {74, 85, 73, 75, 86}},
new() {Name = "Pamela", Scores = new[] {73, 64, 53, 72, 68}},
new() {Name = "Anne", Scores = new[] {78, 96, 52, 79, 60}},
new() {Name = "Fuller", Scores = new[] {59, 68, 88, 85, 76}},
new() {Name = "Cameron", Scores = new[] {70, 73, 75, 51, 98}},
new() {Name = "Aurora", Scores = new[] {65, 70, 53, 80, 52}},
new() {Name = "Anthony", Scores = new[] {68, 69, 94, 88, 98}}
};
var groups = students.GroupBy(s => Math.Round(s.Scores.Average() / 10) * 10).OrderByDescending(s => s.Key);
foreach (var grouping in groups)
{
Console.WriteLine("--------------------------");
Console.WriteLine(grouping.Key);
foreach (var student in grouping)
{
Console.WriteLine(student);
}
Console.WriteLine("--------------------------");
Console.WriteLine();
}
}
}
public class Student
{
public string Name { get; set; }
public int[] Scores { get; set; }
public override string ToString()
{
return $"{nameof(Name)}: {Name}";
}
}
}

Related

Accessing property value from an array of objects c#

I am trying to find the "player" with the highest salary from an array of "BaseBallPlayer" objects. I know I need to loop through the array and compare the salary properties with an "if" statement. However, I cant seem to figure out how to access a specific property from the objects in the array.
here is a snippet of my main():
static void Main(string[] args)
{
BasketBallPlayer basketBP1 = new BasketBallPlayer("Jeff", 24, 30000.00, 12.2, 6, 7, 8);
BasketBallPlayer basketBP2 = new BasketBallPlayer("Jim", 27, 35000, 18, 5, 17, 9);
BasketBallPlayer basketBP3 = new BasketBallPlayer("James", 32, 65000, 34, 87, 15, 12);
object[] BasketBT = new object[] {basketBP1, basketBP2, basketBP3 };
BaseBallPlayer baseBP1 = new BaseBallPlayer("Craig", 26, 53000, 53, 12, 9);
BaseBallPlayer baseBP2 = new BaseBallPlayer("Chris", 35, 66000, 67, 19, 7);
BaseBallPlayer baseBP3 = new BaseBallPlayer("Charlie", 32, 75000, 87, 23, 4);
object[] BaseBT = new object[] { baseBP1, baseBP2, baseBP3 };
foreach (object player in BaseBT)
{
}
}
here is the parent class of BaseBallPlayer:
{
protected int age { get; set; }
protected string name { get; set; }
public double salary { get; set; }
public sportsPlayer(string Name, int Age, double Salary)
{
this.name = Name;
this.age = Age;
this.salary = Salary;
}
public override string ToString()
{
string details = string.Format("Name: {0} \n Age: {1} \n Salary: {2} \n ", this.name, this.age, this.salary);
return details;
}
}
And here is the class BaseBallPlayer:
class BaseBallPlayer: sportsPlayer
{
double battingAverage { get; set; }
int homeRuns { get; set; }
int errors { get; set; }
public BaseBallPlayer(string Name, int Age, double Salary, double BattingAverage, int HomeRuns, int Errors): base(Name, Age, Salary)
{
this.battingAverage = BattingAverage;
this.homeRuns = HomeRuns;
this.errors = Errors;
}
public override string ToString()
{
string details = string.Format("Batting Average: {0} \n Home Runs: {1} \n Errors: {2} \n", this.battingAverage, this.homeRuns, this.errors);
return base.ToString() + details;
}
}
In order to access properties in a type, you should declare variables of that type and not the object type, so your code should look like this in order to be able to access player.salary :
static void Main(string[] args)
{
BasketBallPlayer basketBP1 = new BasketBallPlayer("Jeff", 24, 30000.00, 12.2, 6, 7, 8);
BasketBallPlayer basketBP2 = new BasketBallPlayer("Jim", 27, 35000, 18, 5, 17, 9);
BasketBallPlayer basketBP3 = new BasketBallPlayer("James", 32, 65000, 34, 87, 15, 12);
sportsPlayer[] BasketBT = new object[] {basketBP1, basketBP2, basketBP3 };
BaseBallPlayer baseBP1 = new BaseBallPlayer("Craig", 26, 53000, 53, 12, 9);
BaseBallPlayer baseBP2 = new BaseBallPlayer("Chris", 35, 66000, 67, 19, 7);
BaseBallPlayer baseBP3 = new BaseBallPlayer("Charlie", 32, 75000, 87, 23, 4);
sportsPlayer[] BaseBT = new object[] { baseBP1, baseBP2, baseBP3 };
foreach (sportsPlayer player in BaseBT)
{
// here you can access player.salary
}
}
you have to fix a type of BaseBT as a BaseBallPlayer[]
BaseBallPlayer[] BaseBT = new BaseBallPlayer[] { baseBP1, baseBP2, baseBP3 };
player with max salary
var playerMaxSalary= BaseBT.OrderByDescending(b=>b.salary).FirstOrDefault();
result
Name: Charlie
Age: 32
Salary: 75000
Batting Average: 87
Home Runs: 23
Errors: 4
test
foreach (var player in BaseBT)
{
Console.WriteLine(player.ToString());
}
result:
Name: Craig
Age: 26
Salary: 53000
Batting Average: 53
Home Runs: 12
Errors: 9
Name: Chris
Age: 35
Salary: 66000
Batting Average: 67
Home Runs: 19
Errors: 7
Name: Charlie
Age: 32
Salary: 75000
Batting Average: 87
Home Runs: 23
Errors: 4
you will have the same reslt if you define BaseBT as a List of BaseBallPlayer
List<BaseBallPlayer> BaseBT = new List<BaseBallPlayer> { baseBP1, baseBP2, baseBP3};

TypeScript array equivalent in C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have this array in TypeScript:
public lineChartData:Array<any> = [
{data: [65, 59, 80, 81, 56, 55, 40], label: 'Series A'},
{data: [28, 48, 40, 19, 86, 27, 90], label: 'Series B'},
{data: [18, 48, 77, 9, 100, 27, 40], label: 'Series C'}
];
How would I go about creating the equivalent in C#? I'm new to TypeScript and have never come across the 'any' type.
With anonymous types you could have
var lineChartData = new [] {
new { data = new [] { 65, 59, 80, 81, 56, 55, 40 }, label = "Series A" },
new { data = new [] { 65, 59, 80, 81, 56, 55, 40 }, label = "Series B" }
};
That looks quite close to the Typescript version presented in the question.
It'll be something like this in C#:
var lineChartData = new List<DataLine>
{
new DataLine {Data = new[] {65, 59, 80, 81, 56, 55, 40}, Label = "Series A"},
new DataLine {Data = new[] {28, 48, 40, 19, 86, 27, 90}, Label = "Series B"},
new DataLine {Data = new[] {18, 48, 77, 9, 100, 27, 40}, Label = "Series C"}
};
And every line of your LineChartData will be something like this:
class DataLine
{
public int[] Data { get; set; }
public string Label { get; set; }
}

Check whether the array contains in array of arrays in LINQ expression

I have some problem with my unit test which work with fake Context(means without database connection). On productive environment it work with connection to sql and everything is clear. But with fake context happened something strange - not find array "item.OfferKey" in the array of arrays "validCartItems"
//Array of arrays validCartItems values for example
byte[] offerKey1 = { 30, 163, 252, 225, 36, 208, 128, 47, 64, 244, 34, 199, 28, 57, 110, 215 };
byte[] offerKey2 = { 31, 163, 254, 225, 35, 203, 119, 47, 65, 244, 24, 199, 28, 56, 110, 215 };
byte[][] validCartItems = new byte[4][];
validCartItems[0] = offerKey1;
validCartItems[1] = offerKey1;
validCartItems[2] = offerKey1;
validCartItems[3] = offerKey2;
//Example of ItemPrice in _dataContext.ItemPrices
var itemPriceInFakeContext = new ItemPrice()
{
OfferKey = offerKey1,
//some other properties
};
var itemPrices = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
In this case no elements found. But in case we work with database everithing is all right.
To solve the problem, I wrote the following code:
var itemPricesUncheckOfferKey = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
//&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
List<ItemPrice> itemPrices = new List<ItemPrice>();
foreach (var itemPrice in itemPricesUncheckOfferKey)
{
foreach (var validCartItem in validCartItems.Distinct())
{
if (validCartItem.SequenceEqual(itemPrice.OfferKey))
itemPrices.Add(itemPrice);
}
}
But it does not look like a good solution. Could you tell me the solution within LINQ?
UPD
UnitTest code:
[TestMethod]
public void AddCartItems_Test()
{
User user;
InitUser(out user);
List<AddCartItem> addCartItems;
addCartItems = InitAddCartItem();
ICartService cartService;
InitCartService(out cartService);
List<AddCartItemRezult> addCartItemRezults = cartService.AddCartItems(user, addCartItems);
Assert.AreEqual(4, addCartItemRezults.Count);
int countAllGood = 0;
foreach (var addCartItemRezult in addCartItemRezults)
{
if (addCartItemRezult.IsSuccess) countAllGood++;
}
Assert.AreEqual(1, countAllGood);
}
private void InitCartService(out ICartService cartService )
{
DataFakeContext dataFakeContext = new DataFakeContext();
DataContext_InitUsers(ref dataFakeContext);
DataContext_ItemPrices(ref dataFakeContext);
DataContext_CartItems(ref dataFakeContext);
IDeliveryService deliveryService = new DeliveryFakeService(dataFakeContext);
cartService = new CartService(dataFakeContext, deliveryService);
}
private void DataContext_ItemPrices(ref DataFakeContext dataFakeContext)
{
dataFakeContext.ItemPrices = new ItemPriceDbSet();
byte[] OfferKeyPriv = { 30, 163, 252, 225, 36, 208, 128, 47, 64, 244, 34, 199, 28, 57, 110, 215 };
var itemPrice1 = new DataAccess.Sql.NavisionModel.ItemPrice()
{
Inventory = 2075,
ItemID = "475931",
LineAmount = (decimal)389.9300,
LineAmountWithMargin = (decimal)522.5062,
Multiplicity = 1,
OfferKey = OfferKeyPriv,
//some other properties
};
dataFakeContext.ItemPrices.Add(itemPrice1);
}
I use Repository.Pattern.Ef6;
In your code you're creating byte[] offerKey1 = ... and saving it into itemPriceInFakeContext. And you should use the same variable to adding this into your _dataContext. I mean exactly the same - not the save value but the reference to the same object.
Like this:
//Array of arrays validCartItems values for example
byte[] offerKey1 = { 30, 163, 252, 225, 36, 208, 128, 47, 64, 244, 34, 199, 28, 57, 110, 215 };
byte[] offerKey2 = { 31, 163, 254, 225, 35, 203, 119, 47, 65, 244, 24, 199, 28, 56, 110, 215 };
byte[][] validCartItems = new byte[4][];
validCartItems[0] = offerKey1;
validCartItems[1] = offerKey1;
validCartItems[2] = offerKey1;
validCartItems[3] = offerKey2;
//Example of ItemPrice in _dataContext.ItemPrices
var itemPriceInFakeContext = new ItemPrice()
{
OfferKey = offerKey1, // use the same object
//some other properties
};
// add fake item price to data context
_dataContext.ItemPrices.Add(itemPriceInFakeContext );
var itemPrices = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
That should help.
p.s. you faced this problem because of differences between how runtime compares byte[] and how it does EF and SQL.
In runtime it compares by references. But your LINQ query (on executing) converts this byte[] array (I believe) into the string. And on SQL side it compares the string which will be compared by value.
var itemPrices = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
Your LINQ query seems to have no error in it. Please check the dataContext if it is initialized and whether the connection to the database is ok.

List method to get difference of another list with duplicates (listobject.Expect method does not work)

There are two Lists. I need the difference
List<int> list1 = new List<int>() {18, 13, 22, 24, 20, 20, 27, 31, 25, 28 };
List<int> list2 = new List<int>() {18, 13, 22, 24, 20, 20, 20, 27, 31, 25, 28, 86, 78, 25 };
var listDif = list2.Except(list1);
foreach (var s in listDif)
Console.WriteLine(s);
Console.Read();
the answer should be 20, 86,78, 25
but it only outputs 86,78
If you want exactly that kind of behaviour you should try this:
List<int> list1 = new List<int>() { 18, 13, 22, 24, 20, 20, 27, 31, 25, 28 };
List<int> list2 = new List<int>() { 18, 13, 22, 24, 20, 20, 20, 27, 31, 25, 28, 86, 78, 25 };
// Remove elements of first list from second list
list1.ForEach(l => list2.Remove(l));
list2 = list2.Distinct().ToList();
list2.ForEach(d => Console.WriteLine(d));
Console.Read();
This works fine:
Make a clone of list2
Remove list1 items from list2
Code Sample:
List<int> list1 = new List<int>() { 18, 13, 22, 24, 20, 20, 27, 31, 25, 28 };
List<int> list2 = new List<int>() { 18, 13, 22, 24, 20, 20, 20, 27, 31, 25, 28, 86, 78, 25 };
var diff = list2;
list1.All(x => diff.Remove(x));
You can also perform Remove on list2, however, that will modify list2.
Because you only check which numbers in list1 are missing in list2
But you need to check which numbers in list2 doesn't exist in list1 and in
listDif.
You can do
List<int> diff = new List<int>();
foreach (int num in list1)
{
if (!list2.Contains(num))
{
diff.Add(num);
}
}
foreach (int num in list2)
{
if (!list1.Contains(num) && !diff.contains(num))
{
diff.Add(num);
}
}

Adding many lists

If I have 100 lists (eg x1 to x100), is there a better way of expressing the final line of code?
var x1 = new List<int>() { 75 };
var x2 = new List<int>() { 95, 64 };
var x3 = new List<int>() { 17, 47, 82 };
var x4 = new List<int>() { 18, 35, 87, 10 };
var x5 = new List<int>() { 20, 04, 82, 47, 65 };
var x6 = new List<int>() { 19, 01, 23, 75, 03, 34 };
var x7 = new List<int>() { 88, 02, 77, 73, 07, 63, 67 };
//etc..
var listOfListOfInts = new List<List<int>>() { x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 };
possibly a Dictionary and a for loop to reference all the x1..100.
As long as x1 etc. aren't referenced elsewhere, then write:
var listOfListOfInts = new List<List<int>>()
{
new List<int>() { 75 },
new List<int>() { 95, 64 },
//etc.
};
In fact you shouldn't need to reference the individual variables elsewhere since listOfListOfInts[0] is just as good as x1 for example.
Do you really need these to be of type List<T>? It looks like you're setting up preinitialized data. If you're never going to change the length of any of these "lists", you could use arrays instead; the syntax is more compact:
var listOfListOfInts = new[] {
new[] { 75 },
new[] { 95, 64 },
new[] { 17, 47, 82 },
new[] { 18, 35, 87, 10 },
new[] { 20, 04, 82, 47, 65 },
new[] { 19, 01, 23, 75, 03, 34 },
new[] { 88, 02, 77, 73, 07, 63, 67 },
// ...
};
Perhaps i'm over complicating things but you could do something like
public interface IClass1
{
IList<IList<int>> ListList { get; set; }
void AddList(List<int> nList);
}
public class Class1 : IClass1
{
public IList<IList<int>> ListList { get; set; }
public void AddList(List<int> nList)
{
ListList.Add(nList);
}
}
and then use it like:
public class Create1
{
public Create1()
{
IClass1 iClass1 = new Class1();
iClass1.AddList(new List<int>() { 75 });
}
}

Categories

Resources