I have the following list and I need to transform it to get this result
original list
+----+--------------------+
| key| email |
+====+====================+
| 1 | one#gmail.com |
| 2 | two#gmail.com |
| 1 | three#gmail.com |
| 1 | four#gmail.com |
| 2 | five#gmail.com |
| 2 | six#gmail.com |
+----+----------------+-----
New list the mails concatenated with ;
+----+---------------------------------------------------+
| key| email |
+====+===================================================+
| 1 | one#gmail.com;three#gmail.com;four#gmail.com |
| 2 | two#gmail.com;five#gmail.com;six#gmail.com |
+----+---------------------------------------------------+
How can i accomplish this task with c# Linq? thanks
Try in this way:
x.GroupBy(t => new {t.Id})
.Select(t => new {
Id = t.Key.Id,
email = String.Join(", ", t.Select(p => p.Email).ToArray())
}
Supposing that you have a class similar to this:
public class myEmails
{
public int Key { get; set; }
public string Email { get; set; }
}
and a List<myEmails> that could be like this:
List<myEmails> emails = new List<myEmails>();
You could GroupBy the Key value and then Join all strings (Emails) related to that Key, creating a new Dictionary<int, string> that contains all the Emails grouped by the given Key:
var emailsDictionary = emails
.GroupBy(eml => eml.Key)
.ToDictionary(grp => grp.Key, grp => string.Join(" ", grp.Select(eml => eml.Email)));
Test the result with:
emailsDictionary.ToList().ForEach(dict => Console.WriteLine($"{dict.Key}: {dict.Value}"));
It should give you:
1: one#gmail.com three#gmail.com four#gmail.com
2: two#gmail.com five#gmail.com six#gmail.com
As a note, if you're interested, you could also use Aggregate instead of Join, so this:
grp => string.Join(" ", grp.Select(eml => eml.Email))
could also be expressed as:
grp => grp.Aggregate("", (s, eml) => (eml.Email + " " + s))
Related
How write linq to sql query to retrieve records from table below that (B ,C) be in list c.
Table is in database.
var c = new List<(int,int)>{(1,4), (3,6)};
+---+---+---+
| A | B | C |
+---+---+---+
| a | 1 | 4 |
| b | 2 | 5 |
| c | 3 | 6 |
+---+---+---+
Query should return a and c.
If you are talking about tuples being "fully"(all elements are sequentially equal) equal then you can just use contains:
var c = new List<(int,int)>{(1,3), (3,6)};
var table = new List<(int,int)>{(1,3), (2,5), (3,6)};
var res = table
.Where(i => c.Contains(i))
.ToList();
Equality and tuples
If #Caius Jard's assumption is right then just change .Where(i => c.Contains(i)) to .Where(i => !c.Contains(i))
I am not sure how your logic is but i think you are trying to do something like this,
Let's assume your table model looks like below,
public class MyTable {
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public MyTable(string a, string b, string c) {
A = a;
B = b;
C = c;
}
}
And let's fill the data you have shared and query,
var c = new List<(int, int)> { (1, 4), (3, 6) };
List<MyTable> myTables = new List<MyTable>();
myTables.Add(new MyTable("a", "1", "4"));
myTables.Add(new MyTable("b", "2", "5"));
myTables.Add(new MyTable("c", "3", "6"));
var res = myTables.Where(x => c.Any(y => y.Item1.ToString() == x.B && y.Item2.ToString() == x.C)).Select(x => x.A);
Console.WriteLine(string.Join(" ", res));
Console.ReadKey();
This will print:
a c
I'm stuck rewriting this SQL in Lambda:
SELECT TOP 1000 COUNT(LoginDateTime)
,[LoginDateTime]
,[Culture]
FROM [LearningApp].[dbo].[UserActivities]
group by LoginDateTime, Culture
Result:
+-----+---------------------------+----------+
| | LoginDateTime | Culture |
+-----+---------------------------+----------+
| 1 | 2016-07-14 12:21:23.307 | de |
| 4 | 2016-07-13 12:21:23.307 | en |
| 2 | 2016-07-14 12:21:23.307 | en |
+-----+---------------------------+----------+
And my code:
public List<UserActivityResponseContract> GetUserActivity()
{
var userActivityResponseContracts = new List<UserActivityResponseContract>();
var userActivitiesList = _baseCommands.GetAll<UserActivity>()
.Select(x => new
{
x.LoginDateTime,
x.Culture
})
.GroupBy(x => new { x.LoginDateTime, x.Culture});
foreach (var userActivity in userActivitiesList)
{
userActivityResponseContracts.Add(new UserActivityResponseContract
{
ActivityDate = userActivity.Key.LoginDateTime.ToShortDateString(),
NumberOfTimesLoggedIn = userActivity.Count(),
Culture = userActivity.Key.Culture
});
}
return userActivityResponseContracts;
}
It doesn't seem very difficult but I am a bit stuck.
Method Syntax:
var result = _baseCommands.GetAll<UserActivity>()
.GroupBy(x => new { x.LoginDateTime, x.Culture})
.Select (x => new UserActivityResponseContract
{
ActivityDate = x.Key.LoginDateTime.ToShortDateString(),
Culture = x.Key.Culture,
NumberOfTimesLoggedIn = x.Count()
})
.Take(1000).ToList();
You can also use an overload of GroupBy that enables you to pass the select function as a second parameter
Query Syntax:
var result = (from x in _baseCommands.GetAll<UserActivity>()
group x by new { x.LoginDateTime, x.Culture} into g
select new UserActivityResponseContract
{
ActivityDate = g.Key.LoginDateTime.ToShortDateString(),
Culture = g.Key.Culture,
NumberOfTimesLoggedIn = g.Count()
}).Take(1000).ToList();
To GroupBy just the Date part of this DateTime do: x.LoginDateTime.Date
I need to get a list of players and every team that said player is associated to and add it to my ViewModel.
ViewModel
public class PlayersViewModel
{
public long PlayerID { get; set; }
public string PlayerName { get; set; }
public List<long> TeamID { get; set; } //Players can be assigned to 1 or more teams
}
I have a few different datatables going on:
PlayersInTeams (linking table)
+------------+---------+
| PlayerID | TeamID |
+------------+---------+
| 1 | 10001 |
| 1 | 10002 |
| 2 | 10002 |
| 3 | 10001 |
+------------+---------+
Players
+------------+---------+-----------+
| PlayerID | ForeName| Surname |
+------------+---------+-----------+
| 1 | John | Doe |
| 2 | Pete | Noe |
| 3 | Evan | Soe |
+------------+---------+-----------+
So for the above example tables, Player 1 - John Doe should have an array of 2 teamIDs in the ViewModel [10001, 10002].
Aim
I'm trying to have a List<PlayersViewModel> with a collection of TeamIDs.
Code
public List<PlayersViewModel> GetPlayers()
{
var playersInTeam = new PlayersInTeamsBLL();
var pit = playersInTeam.GetPlayersInTeams();
var playerDetail = Players;
var list = from p in pit
join team in Teams on p.TeamID equals team.TeamID // Only get teams that related to club
join pd in playerDetail on p.PlayerID equals pd.PlayerID //Link a player to
where pd.IsArchived == false
select new PlayersViewModel { TeamID = team.TeamID, PlayerID = p.PlayerID, PlayerName = pd.Forename + " " + pd.Surname};
return list.ToList();
}
I'm getting null PlayerIDs and obviously my TeamID isn't getting populated.
Any suggestions / solutions?
Try something like this:
var viewModels = playerDetail.Select(p => new PlayersViewModel()
{
PlayerID = p.PlayerID,
PlayerName = String.Format("{0} {1}", p.ForeName, p.Surname),
TeamID = pid.Where(pidElement => pidElement.PlayerID == p.PlayerID)
.Select(pidElement => pidElement.TeamID).ToList()
}).ToList();
In general it seems to me you're trying to tackle the problem from the wrong end. You want a list of players first, and then their teams second, not a list of player-team associations first, and player details second, so you should start with the playerDetail object (I assume it's an IEnumerable of all Player objects).
On a side note: consider that you can add a getter to your Player class which would give you the full name without the need to always concatenate the name and surname. Something like:
public string FullName
{
get { return String.Format("{0} {1}", this.FirstName, this.Surname); }
}
var results = yourContext.Players
.Select(p => new PlayersViewModel
{
PlayerID = p.PlayerID,
PlayerName = p.PlayerName,
TeamID = context.PlayersInTeams.Where(x => x.PlayerID == p.PlayerID)
}).ToList();
You need group them using group by like this:
var teamsFinal = from p in pit
join pd in playerDetail on p.PlayerID equals pd.PlayerID
where pd.IsArchived == false
group new {p,pd} by new
{
pd.PlayerID ,
pd.ForeName,
pd.SurName
} into g
select new PlayersViewModel
{
TeamID = g.Select(x => x.p.TeamID).ToList(),
PlayerID = g.Key.PlayerID,
PlayerName = g.Key.ForeName + " " + g.Key.SurName
};
Check this working Fiddle example
I have a table structure like this
id | itemId | date |
1 | a1 | 6/14/2015
2 | a1 | 3/14/2015
3 | a1 | 2/14/2015
4 | b1 | 6/14/2015
5 | c1 | 6/14/2015
From this table structure I am trying to get all the distinct items that has min date. for e.g. I am trying to get id = 3,4 and 5.
I have tried following code but I couldn't
var items = (from i in _db.Items
//where min(i.date) // doesn't seem right
group i by i.itemID
into d select new
{
iId = d.Key,
}).Distinct();
Given your sample data, I would do this:
var query =
from i in _db.Items
group i by i.itemId into gis
let lookup = gis.ToLookup(x => x.date, x => x.id)
from x in lookup[gis.Min(y => y.date)]
select x;
var items = from i in _db.Items
group i.date by i.itemID
into d select new {
iId = d.Key, iDate = d.Min()
};
I have a class:
public class Cards
{
private string _type= string.Empty;
private string _name= string.Empty;
public string Type
{
get { return _type; }
set { _type= value; }
}
public string Name
{
get { return _name; }
set { _name= value; }
}
}
I have an object of this class.
public List<Cards> CardTypes = new List<Cards>();
Values in list Cards is:
Name Type
==============
Visa Vi
Master MA
Discover DI
I have a DataTable cardTable with following columns:
Name,Value,CCvName
+---+------------+-------------+
|Val| Name | CCV |
+---+------------+-------------+
| 1 | Visa | 441 |
| 2 | Master | 121 |
| 3 | Amex | 111 |
| 4 | Diners | 222 |
+---+------------+-------------+
Both List and DataTable have unique values. I want to filter the data from datatable on the basis of Name field in List (delete other records from cardTable). All the values are of string type.
The resulting cardTable should be:
+---+------------+-------------+
|Val| Name | CCV |
+---+------------+-------------+
| 1 | Visa | 441 |
| 2 | Master | 121 |
+---+------------+-------------+
Thanks in advance.
An easy way is to use RowFilter (either on a new DataView or the default DataView of the DataTable).
Given cardTable and cardTypes:
var view = new DataView(cardTable)
{
// create filter: [Name] IN ('Visa','Master','Discover')
RowFilter = String.Format("[Name] IN ({0})", String.Join(",", cardTypes.Select(t => "'" + t.Name + "'")))
};
view now contains the rows you're looking for.
If you really want a LINQ solution, you could use a simple Join:
cardTable = cardTable.AsEnumerable()
.Join(cardTypes,
i => i.Field<string>("Name"),
o => o.Name,
(i, o) => i)
.CopyToDataTable();
You can write LINQ join query returning rows without corresponding card type in list:
var rowsToDelete = from r in cardTable.AsEnumerable()
join c in CardTypes
on r.Field<string>("Name") equals c.Name into g
where !g.Any()
select r;
And then just remove those rows:
foreach(var row in rowsToDelete)
cardTable.Rows.Remove(row);