C# Join string from object with LINQ [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last month.
Improve this question
I currently have an object that I have defined like this.
public class Model {
public string id {get; set;}
public string customer {get; set;}
public string sentence {get; set;}
}
When working with my object I do it in collections which can have repeated elements by id and customer but different sentence, I need to iterate the common elements and join it's sentence like so:
id
customer
sentence
1
001
why
1
001
that
2
002
seperate
I am trying to convert this to the following:
id
customer
sentence
1
001
why, that
2
002
seperate
I currently have this code:
List<Model> data = JsonConvert.DeserializeObject<List<Model>>(json);
List<Model> result = data.GroupBy(x => new {
x.id,
x.customer
}).Select(x => new Model {
id = x.Key.id,
customer = x.Key.customer,
sentence = String.Join(", ", x.Select(z => z.sentence)) // this is what I need to fix
}).ToList();
This however doesn't seem to work, what can I do to fix this. Can anyone help me with this? Thanks in advance.
EDIT:
The tables shown are the visual representation of a List, the first one would be the data variable and the last one how I want the result variable to be. The code doesn't work, it will still return the first visual representation.
My apologies for the unclear question.

There's a code typo, the following works as you need:
List<Model> data = JsonConvert.DeserializeObject<List<Model>>(json);
List<Model> result = data.GroupBy(x => new {
x.id,
x.customer
}).Select(x => new Model {
id = x.Key.id,
customer = x.Key.customer,
sentence = string.Join(", ", x.Select(z => z.sentence))
}).ToList();
Output:
1|001|why, that
2|002|seperate

Related

LINQ GroupBy or something else for a single loop? [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 1 year ago.
Improve this question
This object (greatly simplified) is basically this:
public class Site
{
public string SiteId { get; set; }//unique
public string SiteName { get; set; }
public string NetworkId { get; set; } //unique
public string NetworkName { get; set; }
}
I would like the end result to be:
Network 1
Site 1
Site 2
Network 2
Site 1
Site 2
Site 3
Edit for clarity:
I could just outer loop all the networks and then inner loop all the sites that belong to that network.
I'm using 2 loops. One outer one for the unique NetworkId and one inner one for the unique SiteId.
I was wondering if there was a way to accomplish the same result with a single loop. I realize that a GroupBy return IEnumerable<IGrouping<TKey, TElement>> but I'm not sure how to use that for my preferred result.
Edit adding details:
Can I accomplish the end result in a single foreach loop if I use a GroupBy?
How would I accomplish the end result output if I used a GroupBy on the NetworkId?
thanks!
Yes, GroupBy is your friend. What should be the end result? Maybe a Dictionary<(string, string), List<Site>> where the key is the combination of NetworkId and NetworkName(in case the name is not unique)?
Dictionary<(string Id, string Name), List<Site>> networkSites = allSites
.GroupBy(s => (s.NetworkId, s.NetworkName))
.ToDictionary(g => g.Key, g => g.OrderBy(s => s.SiteId).ToList());
Output:
foreach(var kv in networkSites)
{
Console.WriteLine($"{kv.Key.Name} {kv.Key.Id}");
foreach(var site in kv.Value)
Console.WriteLine($"{site.SiteName} {site.SiteId}");
}
using linq
var result = sites.GroupBy(x => x.NetworkName).ToDictionary(x => x.Key, y => y.Select(x=>x.SiteId).ToArray());
Rather than GroupBy followed by ToDictionary, you could create a lookup:
var lookup = sites.ToLookup(x => x.NetworkId, x => x.SiteId);
The Lookup<TKey, TValue> is an immutable structure that allows an IEnumerable<TValue> to be retrieved using an indexer:
var sitesForNetwork1 = lookup[1];

C# LINQ Combine values of 2 lists [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a list with tickets in it:
TicketID - Aantal (amount) - ActiePrijs (price)
For all those tickets the ActiePrijs (price) is still empty. But I also have a list with only those Actieprijs (prices). It's just a list of decimals.
Now I want to put the first actiePrijs from the decimal list into the ActiePrijs from the first ticket, the second ActiePrijs into the ActiePrijs of the second ticket etc.
I want to do it using linq method syntax.
Can someone help me?
I assume tickets & price lists are tickets and price.
You can use linq like below.
tickets = tickets.Select((ticket, index) => new Ticket
{
TicketID = ticket.TicketID,
Aantal = ticket.Aantal,
ActiePrijs = price[index]
})
.ToList();
Or if you have more properties and you do not want to create new object then use like below.
tickets = tickets.Select((ticket, index) =>
{
ticket.ActiePrijs = price[index];
return ticket;
})
.ToList();
You dont show any code, but I thing you want something like this.
public class Properties
{
public int Aantal { get; set; }
public int Price { get; set; }
}
List<Properties> l = new List<Properties>();
l.Add(new Properties() { Aantal = 1 });
l.Add(new Properties() { Aantal = 2 });
l.Add(new Properties() { Aantal = 3 });
List<int> l2 = new List<int>();
l2.Add(1);
l2.Add(2);
l2.Add(3);
int index = 0;
l.ForEach(x => x.Price = l2[index++]);

Entity Framework - Query to obtain last 2 unique entries of a column and then their relevant data

I am new to entity framework and I am having difficulty coming up with a query. For the following situation.Say I have the following model
class Student
{
[Key]
public int Id { get; set; }
public string name{get;set;}
public string guid{get;set;}
}
and my table looks like this
id| name | guid
--------------
1 Andrew | C
2 John | D
3 Adam | B
4 Charles| A
5 Jacob | A
Now I would like to get the last two unique GUIDs which will be A and B.
and then I would like to get all row in which these GUIS appeared in the table. so I would like Jacob,Charles and Adam returned. Any suggestions on how I can get started with this ? I know Ill have to sortby then select unique. But I am not sure how Ill do it in Entity.
I think you could do something like this:
var result = dbcontext.Students.OrderByDescending(s => s.Id)
.GroupBy(s => s.Guid)
.Take(2)
.SelectMany(s => s.Take(1));
1- Order by Id descending to get to the last Id's first.
2- Then group by the Guid and take the first 2 groups.
3- Select the top 1 for each group.
You need to only use this if you want output as Jacob,Charles and Adam
Original Credits #Stackberg use suggested query like without Take if the indented result.
//This work against in memory list (TESTED)
var result = dbcontext.Students.OrderByDescending(s => s.Id)
.GroupBy(s => s.Guid)
.Take(2)
.SelectMany(s=>s.ToList());
//IF EF doesn't able to convert the query you can try this.
var inMemoryGrouped = dbcontext.Students.OrderByDescending(s => s.Id)
.GroupBy(s => s.Guid)
.Take(2)
.ToList();
//Flatten the items using select many
var final = inMemoryGrouped.SelectMany(y=>y.ToList());
Only thing it differ from #Stackberg answer is omitted the Take after grouping.

Dictionary problems: results.Read<NotificationRule>().ToDictionary(rule => rule.Id) states duplicate key

I have a slight problem I don't seem to understand.
I have this bit of code:
SELECT sr.RuleId, s.Id, s.Name FROM Sites s
INNER JOIN NotificationSiteRules sr ON s.Id = sr.SiteID
WHERE sr.RuleId IN (
SELECT r.Id FROM NotificationRules r
INNER JOIN NotificationSiteRules sr ON r.Id = sr.RuleId
WHERE r.IsDeleted = 0 AND (#siteId IS NULL OR sr.SiteId = #siteId)
)
which returns the following set:
1 1 SiteOne
3 1 SiteOne
7 1 SiteOne
1 5 SiteTwo
As you can see, for rule 1 I have both SiteOne and SiteTwo. This must be permitted.
The definition of NotificationRule object is:
public class NotificationRule
{
public NotificationRule()
{
Sites = new List<Site>();
Recipients = new List<Recipient>();
}
public int? Id { get; set; }
public string Name { get; set; }
public List<Site> Sites { get; set; }
public List<Recipient> Recipients { get; set; }
}
So in this definition, it's actually stated that by each Id I should be able to have a list of Sites... But I am getting
System.ArgumentException: An item with the same key has already been added.
when I do
var rules = results.Read<NotificationRule>().ToDictionary(rule => rule.Id);
What am I doing wrong?
Sorry, I am editing the question because I am afraid I was not clear as to what I am trying to achieve.
The final result I was hoping for is of this form:
{1, [1,5],[SiteOne, SiteTwo]}
Which would correspond to:
{Key, List<Recipient>, list<Site>}
As you can see, in this construct I wouldn't have two keys, because all ends up into the same element.
As long as objects in the collection results have not unique values in the field Id you have to group results before put them to the dictionary.
results.Read<NotificationRule>()
.GroupBy(rule=>rule.Id).ToDictionary(group => group.Key, group=>group.ToArray());
It sounds like you may be wanting to do a group by rather than creating a dictionary.
var rules = results.Read<NotificationRule>().GroupBy(k => rule.Id);
This will group the rules by rule.Id
or if you are just trying to get the sites for a specific rule you could do
var siteId = 1;
var sites = results.Read<NotificationRule>().Where(r => r.Id == siteId);
Actually I just found that the problem is not in that little bit of code; that one is handled ok. The problem is that #siteId is arriving null, and then I get duplicates in a previous query.
I am closing this question as the point is now moot; I need to figure out a way to fix the previous query to get me the correct value... or a way to handle that null.
Thank you all for your help!

C# linq group By on field and result string? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
how to write dynamic groupby with selectfieldString and resultFieldString?
sample:
public class Customer
{
public int Id;
public string Name;
public string LastName;
public decimal Amount;
}
var lst = new List<Customer>();
lst.Add(new Customer { Id = 1, Name = "vahid", LastName = "Aghilpour", Amount = 15 });
lst.Add(new Customer { Id = 1, Name = "hamid", LastName = "rezaei", Amount = 35 });
lst.Add(new Customer { Id = 1, Name = "vahid", LastName = "Aghilpour", Amount = 15 });
string[] field = { "Name", "LastName" };
string aggrigatefield = "Sum(Amount)";
lst.GroupBy(field).Select(aggrigatefield);---??????????
By using dynamic linq you should be able to do it.
// Remember: using System.Linq.Dynamic;
// The format for the key of the GroupBy is "new(field1,field2)"
// "it" as elementSelector means "the full object"
string field = string.Format("new({0})", string.Join(",", fields));
decimal[] res = lst.GroupBy(field, "it")
.Select(aggrigatefield)
.Cast<decimal>()
.ToArray();
Note that if the Select is totally dynamic (so it could return a Sum(), or a string field, or a decimal field, or a complex object or a ???), then you can't really do a Cast<decimal>(), because you "statically" don't know the type of the returned object. You have to do
object[] res = lst.GroupBy(field, "it")
.Select(aggrigatefield)
.Cast<object>()
.ToArray();
or
dynamic[] res = lst.GroupBy(field, "it")
.Select(aggrigatefield)
.Cast<dynamic>()
.ToArray();

Categories

Resources