Count list with parameters? - c#

I have two class lists teams, and matches
In my teams class I have a int id and string name and on the matches class I have int team1Id and
team2Id, I want to know if there's a way to count on matches list how many matches a team participate..
Like
if(teamlist.id == matcheslist.team1 || teamlist.id == matcheslist.team2) count++;
Sorry if I didn't explain very well, english isn't my first language.
EDIT1:
Here the lists,
public List teams= new List();
public List matches = new List();
Team and Match are my classes, with basic information, id and name for Team and id, team1 and team2 for Match, I tried to use find but it only return one result

Given this sort of setup:
class Team {
public int TeamId { get; set; }
}
class Match {
public Team[] Teams { get; set; }
}
var matches = new List<Match>() {
new Match() {
Teams = new Team[] {
new Team() { TeamId = 1 },
new Team() { TeamId = 2 }
}
},
new Match() {
Teams = new Team[] {
new Team() { TeamId = 1 },
new Team() { TeamId = 15 }
}
}
};
You can count them like so:
var teamOneGameCount = matches.Count(match => match.Teams.Any(team => team.TeamId == 1));
var teamTwoGameCount = matches.Count(match => match.Teams.Any(team => team.TeamId == 2));
var teamFifteenGameCount = matches.Count(match => match.Teams.Any(team => team.TeamId == 15));

here is linq example:
List<Teamlist> item1 = new List<Teamlist>();
List<Matcheslist> item2 = new List<Matcheslist>();
var count = item1.Count(c => item2.Any(c2 => c2.Id2 == c.Id1));

I think you want something like:
List<teamlist> list = new List<teamlist>();
int count = 0;
list.Add(team1);
list.Add(team2);
...
foreach(teamlist tl in list)
{
if(teamlist.id == matcheslist.team1 || teamlist.id == matcheslist.team2) count++;
}
Is that "List" keyword you need ?
Or you need a LINQ query operation like:
using System.Linq;
...
List<int> list = new List<int>();
list.AddRange(new []{1,2,3,4,5,6});
int count = list.Count(n => n > 2); // 4

Related

Find two values in hierarchical object tree C# using Linq

I have the following structures:
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var tourn = new Tournament();
var player = new Player() { Type = PlayerType.User };
var seat1 = new Seat() { Number = 1, Player = player } ;
tourn.Tables = new List<Table>() { new Table(){ Seats = new List<Seat>(){seat1} } };
//Console.WriteLine(tourn.Tables.Where((k=> k.Tables.Any(m=> m.Seats.Any(j=> j.Player == Player.User)))).Count());
// Get Table and Seat numbers for PlayerType.User
}
public class Seat{
public Player? Player {get;set;}
public int Number {get;set;}
}
public enum PlayerType {
User,
Bot
}
public class Tournament{
public List<Table> Tables {get;set;}
}
public class Table
{
public List<Seat> Seats {get;set;}
public int Number {get;set;}
}
public class Player
{
public PlayerType Type { get; set; }
}
}
I have want the table and seat number where the playertype = user
Is it possible to build a Linq query to do this in one statement?
(I have looked at many examples and can't seem to get it right)
Tried this:
var playerLocation = tables
.Select(seat => new
{
TableNumber = seat.TableNumber,
TableSeat = seat.Seats
.Where(s => s.Player is not null &&
s.Player.Type == PlayerType.User)
.Select(st => new
{
SeatNumber = st.Number
})
});
Fiddle (.NET Core): https://dotnetfiddle.net/CMjZs6
I cheated...
PlayerLocation location = new PlayerLocation();
foreach (Table table in tables)
foreach (Seat seat in table.Seats)
if (seat.Player is not null && seat.Player.Type == PlayerType.User)
{
location.TableNumber = table.TableNumber;
location.SeatNumber = seat.Number;
break;
}
Assuming you want the answer as an object with the table number and a list of seat numbers, it is straightforward:
var ans = tourn.Tables.Select(t => new {
t.Number,
Seats = t.Seats.Where(s => s.Player?.Type == PlayerType.User)
.Select(s => s.Number)
.ToList()
});
Based On your Updated Fiddle
var anonyType = tourn.Tables.Where(k=> k.Seats.Any(j=> j.Player?.Type == PlayerType.User)).Select(k=> new { TableNumber = k.Number, SeatNumbers = k.Seats.Select(j=> j.Number) }).FirstOrDefault();
Console.WriteLine(anonyType.TableNumber);
Console.WriteLine(String.Join(" , ", anonyType.SeatNumbers));

Best approach to compare if one list is subset of another in C#

I have the below two classes:
public class FirstInner
{
public int Id { get; set; }
public string Type { get; set; }
public string RoleId { get; set; }
}
public class SecondInner
{
public int Id { get; set; }
public string Type { get; set; }
}
Again, there are lists of those types inside the below two classes:
public class FirstOuter
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public List<FirstInner> Inners { get; set; }
}
public class SecondOuter
{
public int Id { get; set; }
public string Name { get; set; }
public List<SecondInner> Inners { get; set; }
}
Now, I have list of FirstOuter and SecondOuter. I need to check if FirstOuter list is a subset of SecondOuter list.
Please note:
The names of the classes cannot be changed as they are from different systems.
Some additional properties are present in FirstOuter but not in SecondOuter. When comparing subset, we can ignore their presence in SecondOuter.
No.2 is true for FirstInner and SecondInner as well.
List items can be in any order---FirstOuterList[1] could be found in SecondOuterList[3], based on Id, but inside that again need to compare that FirstOuterList[1].FirstInner[3], could be found in SecondOuterList[3].SecondInner[2], based on Id.
I tried Intersect, but that is failing as the property names are mismatching. Another solution I have is doing the crude for each iteration, which I want to avoid.
Should I convert the SecondOuter list to FirstOuter list, ignoring the additional properties?
Basically, here is a test data:
var firstInnerList = new List<FirstInner>();
firstInnerList.Add(new FirstInner
{
Id = 1,
Type = "xx",
RoleId = "5"
});
var secondInnerList = new List<SecondInner>();
secondInner.Add(new SecondInner
{
Id = 1,
Type = "xx"
});
var firstOuter = new FirstOuter
{
Id = 1,
Name = "John",
Title = "Cena",
Inners = firstInnerList
}
var secondOuter = new SecondOuter
{
Id = 1,
Name = "John",
Inners = secondInnerList,
}
var firstOuterList = new List<FirstOuter> { firstOuter };
var secondOuterList = new List<SecondOuter> { secondOuter };
Need to check if firstOuterList is part of secondOuterList (ignoring the additional properties).
So the foreach way that I have is:
foreach (var item in firstOuterList)
{
var secondItem = secondOuterList.Find(so => so.Id == item.Id);
//if secondItem is null->throw exception
if (item.Name == secondItem.Name)
{
foreach (var firstInnerItem in item.Inners)
{
var secondInnerItem = secondItem.Inners.Find(sI => sI.Id == firstInnerItem.Id);
//if secondInnerItem is null,throw exception
if (firstInnerItem.Type != secondInnerItem.Type)
{
//throw exception
}
}
}
else
{
//throw exception
}
}
//move with normal flow
Please let me know if there is any better approach.
First, do the join of firstOuterList and secondOuterList
bool isSubset = false;
var firstOuterList = new List<FirstOuter> { firstOuter };
var secondOuterList = new List<SecondOuter> { secondOuter };
var jointOuterList = firstOuterList.Join(
secondOuterList,
p => new { p.Id, p.Name },
m => new { m.Id, m.Name },
(p, m) => new { FOuterList = p, SOuterList = m }
);
if(jointOuterList.Count != firstOuterList.Count)
{
isSubset = false;
return;
}
foreach(var item in jointOuterList)
{
var jointInnerList = item.firstInnerList.Join(
item.firstInnerList,
p => new { p.Id, p.Type },
m => new { m.Id, m.type },
(p, m) => p.Id
);
if(jointInnerList.Count != item.firstInnerList.Count)
{
isSubset = false;
return;
}
}
Note: I am assuming Id is unique in its outer lists. It means there will not be multiple entries with same id in a list. If no, then we need to use group by in above query
I think to break the question down..
We have two sets of Ids, the Inners and the Outers.
We have two instances of those sets, the Firsts and the Seconds.
We want Second's inner Ids to be a subset of First's inner Ids.
We want Second's outer Ids to be a subset of First's outer Ids.
If that's the case, these are a couple of working test cases:
[TestMethod]
public void ICanSeeWhenInnerAndOuterCollectionsAreSubsets()
{
HashSet<int> firstInnerIds = new HashSet<int>(GetFirstOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> firstOuterIds = new HashSet<int>(GetFirstOuterList().Select(outer => outer.Id).Distinct());
HashSet<int> secondInnerIds = new HashSet<int>(GetSecondOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> secondOuterIds = new HashSet<int>(GetSecondOuterList().Select(outer => outer.Id).Distinct());
bool isInnerSubset = secondInnerIds.IsSubsetOf(firstInnerIds);
bool isOuterSubset = secondOuterIds.IsSubsetOf(firstOuterIds);
Assert.IsTrue(isInnerSubset);
Assert.IsTrue(isOuterSubset);
}
[TestMethod]
public void ICanSeeWhenInnerAndOuterCollectionsAreNotSubsets()
{
HashSet<int> firstInnerIds = new HashSet<int>(GetFirstOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> firstOuterIds = new HashSet<int>(GetFirstOuterList().Select(outer => outer.Id).Distinct());
HashSet<int> secondInnerIds = new HashSet<int>(GetSecondOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> secondOuterIds = new HashSet<int>(GetSecondOuterList().Select(outer => outer.Id).Distinct());
firstInnerIds.Clear();
firstInnerIds.Add(5);
firstOuterIds.Clear();
firstOuterIds.Add(5);
bool isInnerSubset = secondInnerIds.IsSubsetOf(firstInnerIds);
bool isOuterSubset = secondOuterIds.IsSubsetOf(firstOuterIds);
Assert.IsFalse(isInnerSubset);
Assert.IsFalse(isOuterSubset);
}
private List<FirstOuter> GetFirstOuterList() { ... }
private List<SecondOuter> GetSecondOuterList() { ... }

Linq Join Not Equal

I have 3 classes:
public class HoteAvail
{
public int HotelID { get; set; }
public string Name { get; set; }
public List<Room> Rooms { get; set; }
}
public class Room
{
public int RoomID { get; set; }
public string RoomName { get; set; }
}
public class DAL
{
public static List<HoteAvail> GetAll()
{
return new List<HoteAvail>()
{
new HoteAvail{HotelID=1,Name="Taj",Rooms=new List<Room>(){new Room{RoomID=1,RoomName="Deliux"}}},
new HoteAvail{HotelID=2,Name="x",Rooms=new List<Room>(){new Room{RoomID=2,RoomName="dd"},new Room{RoomID=1,RoomName="qq"}}},
new HoteAvail{HotelID=3,Name="y",Rooms=new List<Room>(){new Room{RoomID=3,RoomName="yy"},new Room{RoomID=1,RoomName="rr"}}},
};
}
public static List<HoteAvail> GetAllII()
{
return new List<HoteAvail>()
{
new HoteAvail{HotelID=1,Name="Taj",Rooms=new List<Room>(){new Room{RoomID=1,RoomName="Deliux"},new Room{RoomID=1,RoomName="pp"}}},
new HoteAvail{HotelID=4,Name="x",Rooms=new List<Room>(){new Room{RoomID=2,RoomName="dd"},new Room{RoomID=1,RoomName="qq"}}},
new HoteAvail{HotelID=5,Name="y",Rooms=new List<Room>(){new Room{RoomID=3,RoomName="yy"},new Room{RoomID=1,RoomName="rr"}}},
};
}
}
I want to join the values of DAL.GetAll() and DAL.GetAllII() and result should contain only those values whose HotelID doesnot matches.
The final result set should be like :
new HoteAvail{HotelID=2,Name="x",Rooms=new List<Room>(){new Room{RoomID=2,RoomName="dd"},new Room{RoomID=1,RoomName="qq"}}},
new HoteAvail{HotelID=3,Name="y",Rooms=new List<Room>(){new Room{RoomID=3,RoomName="yy"},new Room{RoomID=1,RoomName="rr"}}},
new HoteAvail{HotelID=4,Name="x",Rooms=new List<Room>(){new Room{RoomID=2,RoomName="dd"},new Room{RoomID=1,RoomName="qq"}}},
new HoteAvail{HotelID=5,Name="y",Rooms=new List<Room>(){new Room{RoomID=3,RoomName="yy"},new Room{RoomID=1,RoomName="rr"}}}
I tried:
var groupBNames = new HashSet<string>(DAL.GetAll().Select(x => x.HotelID.ToString()));
var filteredEmployees = DAL.GetAllII().Where(x => !groupBNames.Contains(x.HotelID.ToString()));
var resultList = from a in DAL.GetAll()
where !(DAL.GetAllII().Any(HotelID => HotelID == a))
select a;
But I am not getting any success. Thanks in advance.
I'd recommend doing 2 excepts using a custom IEqualityComparer. You can use this method to create the comparer:
// create a comparer to compare HotelAvail objects by hotelId
// see http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/
// for the implementation of EqualityComparers.Create, which is a nice shortcut
var comparer = EqualityComparers.Create<HoteAvail>(ha => ha.HotelId); // compare by hotelId
var results =
// first take all entries in GetAll() NOT IN GetAllII()
DAL.GetAll().Except(DAL.GetAllII(), comparer)
// then add all entries in GetAllII() NOT IN GetAll()
.Concat(DAL.GetAllII()).Except(DAL.GetAll(), comparer);
You could implement a custom IEqualityComparer<HoteAvail>:
public class HoteAvailComparer: IEqualityComparer<HoteAvail>
{
public bool Equals(HoteAvail x, HoteAvail y)
{
return x != null && y != null && x.HotelID == y.HotelID;
}
public int GetHashCode(HoteAvail obj)
{
return obj.HotelID;
}
}
that you can use for Enumerable.Except which is efficient since it's using a set:
var resultList = DAL.GetAll().Except(DAL.GetAllII(), new HoteAvailComparer());
Console.WriteLine(String.Join(",", resultList.Select(h => h.HotelID))); // 2,3
Update
It is giving me HotelId 2, 3 where as I want to join the values of
DAL.GetAll() and DAL.GetAllII() and result should contain only those
values whose HotelID doesnot matchesi.e. The result should have
HotelId 2,3,4,5
Then you need to use Except from both perspectives:
var hotelComparer = new HoteAvailComparer();
var all1 = DAL.GetAll();
var all2 = DAL.GetAllII();
var resultList = all1.Except(all2, hotelComparer).Concat(all2.Except(all1, hotelComparer));
The desired result 2,3,4,5:
Console.WriteLine(String.Join(",", resultList.Select(h => h.HotelID)));
Of course you could also use Concat and GroupBy, but it's less efficient and maintainable:
resultList = all1.Concat(all2).GroupBy(h => h.HotelID)
.Where(g => g.Count() == 1)
.SelectMany(g => g);
You can use the IEqualityComparer<HoteAvail> for many other LINQ methods like GroupBy+Distinct,Join,Intersect etc.

Remove Items from sub list matching another sub list with Linq

I have the following classes ( simplified ):
public class SeguradoraCalculo
{
public int CodigoSeguradora { get; set; }
public List<Franquia> Franquias{get;set;}
}
public class Franquia {
public int CodFranquia{get;set;}
}
And i have the following data:
var allData = new List<SeguradoraCalculo>(){new SeguradoraCalculo(){
CodigoSeguradora = 11,
Franquias = new List<Franquia>()
{
new Franquia()
{
CodigoFranquia = 1
},
new Franquia()
{
CodigoFranquia = 2
}
}
}
};
var except = new List<SeguradoraCalculo>()
{
new SeguradoraCalculo()
{
CodigoSeguradora = 11,
Franquias = new List<Franquia>()
{
new Franquia()
{
CodigoFranquia = 1
}
}
}
};
How can i have a result that, removing items that match CodigoSeguradora and CodigoFranquia, existing Franquias are removed and i get SeguradoraCalculo only if i have at least one Franquia in my Franquias List?
In this example my final list would be:
CodigoSeguradora = 11,
Franquias = new List<Franquia>()
{
new Franquia()
{
CodigoFranquia = 2
}
}
Thanks
First join the two collections, based on the key, then go through each joined pair and remove all items from the first that are contained in the second:
var query = allData.Join(except,
item => item.CodigoSeguradora,
item => item.CodigoSeguradora,
(a, b) => new { a, b });
foreach (var pair in query)
pair.a.Franquias.RemoveAll(f =>
pair.b.Franquias.Select(x => x.CodFranquia).Contains(f.CodFranquia));

LINQ Query to Filter Items By Criteria From Multiple Lists

I'm having trouble conceptualizing something that should be fairly simple using LINQ. I have a collection that I want to narrow down, or filter, based on the id values of child objects.
My primary collection consists of a List of Spots. This is what a spot looks like:
public class Spot
{
public virtual int? ID { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string TheGood { get; set; }
public virtual string TheBad { get; set; }
public virtual IEnumerable<Season> Seasons { get; set; }
public virtual IEnumerable<PhotographyType> PhotographyTypes { get; set; }
}
I'm trying to filter the list of Spots by PhotographyType and Season. I have a list of ids for PhotographyTypes and Seasons, each in an int[] array. Those lists look like this:
criteria.PhotographyTypeIds //an int[]
criteria.SeasonIds //an int[]
I want to build a collection that only contains Spots with child objects (ids) matching those in the above lists. The goal of this functionality is filtering a set of photography spots by type and season and only displaying those that match. Any suggestions would be greatly appreciated.
Thanks everyone for the suggestions. I ended up solving the problem. It's not the best way I'm sure but it's working now. Because this is a search filter, there are a lot of conditions.
private List<Spot> FilterSpots(List<Spot> spots, SearchCriteriaModel criteria)
{
if (criteria.PhotographyTypeIds != null || criteria.SeasonIds != null)
{
List<Spot> filteredSpots = new List<Spot>();
if (criteria.PhotographyTypeIds != null)
{
foreach (int id in criteria.PhotographyTypeIds)
{
var matchingSpots = spots.Where(x => x.PhotographyTypes.Any(p => p.ID == id));
filteredSpots.AddRange(matchingSpots.ToList());
}
}
if (criteria.SeasonIds != null)
{
foreach (int id in criteria.SeasonIds)
{
if (filteredSpots.Count() > 0)
{
filteredSpots = filteredSpots.Where(x => x.Seasons.Any(p => p.ID == id)).ToList();
}
else
{
var matchingSpots = spots.Where(x => x.Seasons.Any(p => p.ID == id));
filteredSpots.AddRange(matchingSpots.ToList());
}
}
}
return filteredSpots;
}
else
{
return spots;
}
}
You have an array of IDs that has a Contains extension method that will return true when the ID is in the list. Combined with LINQ Where you'll get:
List<Spot> spots; // List of spots
int[] seasonIDs; // List of season IDs
var seasonSpots = from s in spots
where s.ID != null
where seasonIDs.Contains((int)s.ID)
select s;
You can then convert the returned IEnumerable<Spot> into a list if you want:
var seasonSpotsList = seasonSpots.ToList();
This may helps you:
List<Spot> spots = new List<Spot>();
Spot s1 = new Spot();
s1.Seasons = new List<Season>()
{ new Season() { ID = 1 },
new Season() { ID = 2 },
new Season() { ID = 3 }
};
s1.PhotographyTypes = new List<PhotographyType>()
{ new PhotographyType() { ID = 1 },
new PhotographyType() { ID = 2 }
};
Spot s2 = new Spot();
s2.Seasons = new List<Season>()
{ new Season() { ID = 3 },
new Season() { ID = 4 },
new Season() { ID = 5 }
};
s2.PhotographyTypes = new List<PhotographyType>()
{ new PhotographyType() { ID = 2 },
new PhotographyType() { ID = 3 }
};
List<int> PhotographyTypeIds = new List<int>() { 1, 2};
List<int> SeasonIds = new List<int>() { 1, 2, 3, 4 };
spots.Add(s1);
spots.Add(s2);
Then:
var result = spots
.Where(input => input.Seasons.All
(i => SeasonIds.Contains(i.ID))
&& input.PhotographyTypes.All
(j => PhotographyTypeIds.Contains(j.ID))
).ToList();
// it will return 1 value
Assuming:
public class Season
{
public int ID { get; set; }
//some codes
}
public class PhotographyType
{
public int ID { get; set; }
//some codes
}

Categories