Sebastian
Sebastian

Reputation: 4811

Join string with same property using LINQ

I have a model like below

public class PropsModel
{
    public int props_id { get; set; }
    public string props_name { get; set; }
    public int props_order { get; set; }
}

Sample values

[
   { 1, "red" ,0 }
   { 2, "green", 3}
   { 1, "light red" ,1 }
   { 3, "yellow", 2}
   { 2, "blue", 6}    
]

Result STRING : "red/light red" , "yellow" , "green/blue"

Output string rules

Current implementation

    List<string> _inflections = new List<string>();
    var distinctIDs = inflections_model.Select(x => x.form_id).Distinct(); //find distinct IDs
    foreach (int _id in distinctIDs) //for each distinct ID , join the string  to LIST
    {
     string inflection_val = string.Join(" / ", from item in inflections_model 
                                                      where item.form_id==_id
                                                      select item.props_name );
        _inflections.Add(inflection_val);
    }
    string inflection_string = string.Join(", ", _inflections);  //combine processed STRINGS to a comma separate list 

This produces needed result , but not in the order (props_order is not used anywhere).

Can we make this to a single LINQ query?

Upvotes: 0

Views: 562

Answers (5)

Furkan &#214;zt&#252;rk
Furkan &#214;zt&#252;rk

Reputation: 1416

var list = models.OrderBy(x => x.props_order).ToLookup(x => x.props_id, x => x.props_name).Select(name => string.Join("/", name));
var result = string.Join(",", list);

Prints

"red/light red,yellow,green/blue"

Better performance with Lookup

On machine,

GroupBy => takes 1.6215 milliseconds

Lookup => takes 0.2072 milliseconds

Upvotes: 1

Prasad Telkikar
Prasad Telkikar

Reputation: 16089

You can try below implementation

var groups = list.GroupBy(x => x.props_id); //Group By Id

List<string> stringList = new List<string>(); //stringList to store common records with /
foreach(var grp in groups)
    stringList.Add(string.Join("/", list.Where(x => x.props_id == grp.Key).Select(y => y.props_name)));  //Logic to select property names from common groups

Console.WriteLine(string.Join(", ", stringList)); //Print result

Output:

red/light red, green/blue, Yellow

.NET Fiddle

Upvotes: 2

fenixil
fenixil

Reputation: 2134

You may use LINQ GroupBy and Select:

var data = inflections_model.GroupBy(p=> p.props_id) // this gives you groups
  .Select(g =>  
      String.Join("/", g.OrderBy(r=>r.props_order)
                        .Select(r=>r.props_name)))  
var inflection_string = string.Join(", ",data)

Upvotes: 2

Selim Yildiz
Selim Yildiz

Reputation: 5380

You need to GroupBy items props_id and OrderBy props_order as following one single LINQ:

    var _inflections = inflections_model.OrderBy(o => o.props_order)
                                                .GroupBy(i => i.props_id)
                                                .Select(s => String.Join("/", s.Select(p => p.props_name)));

    var inflection_string = String.Join(",", _inflections);

It will give following result as desired:

"red/light red","yellow","green/blue"

Upvotes: 2

max
max

Reputation: 488

This orders the groups of elements based on the lowest value of props_order in each group

string.Join(", ",
    inflections_model
        .GroupBy(o => o.props_id)
        .OrderBy(g => g.Min(o => o.props_order))
        .Select(g => string.Join("/", g.Select(o => o.props_name))));

Upvotes: 2

Related Questions