String Join Using a Lambda Expression - c#

If I have a list of some class like this:
class Info {
public string Name { get; set; }
public int Count { get; set; }
}
List<Info> newInfo = new List<Info>()
{
{new Info { Name = "ONE", Count = 1 }},
{new Info { Name = "TWO", Count = 2 }},
{new Info { Name = "SIX", Count = 6 }}
};
Can a Lambda expression be used to string join the attributes in the list of classes like this:
"ONE(1), TWO(2), SIX(6)"

string.Join(", ", newInfo.Select(i => string.Format("{0}({1})", i.Name, i.Count)))
You could also override ToString.
class Info
{
....
public override ToString()
{
return string.Format("{0}({1})", Name, Count);
}
}
... and then the call is dead simple (.Net 4.0):
string.Join(", ", newInfo);

String.Join(", ", newInfo.Select(i=>i.Name+"("+i.Count+")") );

You Can use as like following
You can Return a specific type like this
Patient pt = dc.Patients.Join(dc.PatientDetails, pm => pm.PatientId, pd => pd.PatientId,
(pm, pd) => new
{
pmm = pm,
pdd = pd
})
.Where(i => i.pmm.PatientCode == patientCode && i.pmm.IsActive || i.pdd.Mobile.Contains(patientCode))
.Select(s => new Patient
{
PatientId = s.pmm.PatientId,
PatientCode = s.pmm.PatientCode,
DateOfBirth = s.pmm.DateOfBirth,
IsActive = s.pmm.IsActive,
UpdatedOn = s.pmm.UpdatedOn,
UpdatedBy = s.pmm.UpdatedBy,
CreatedOn = s.pmm.CreatedOn,
CreatedBy = s.pmm.CreatedBy
})
Or You can retrieve anonymous type like this
var patientDetails = dc.Patients.Join(dc.PatientDetails, pm => pm.PatientId, pd => pd.PatientId,
(pm, pd) => new
{
pmm = pm,
pdd = pd
})
.Where(i => i.pmm.PatientCode == patientCode && i.pmm.IsActive || i.pdd.Mobile.Contains(patientCode))
.Select(s => new
{
PatientId = s.pmm.PatientId,
PatientCode = s.pmm.PatientCode,
DateOfBirth = s.pmm.DateOfBirth,
IsActive = s.pmm.IsActive,
PatientMobile = s.pdd.Mobile,
s.pdd.Email,
s.pdd.District,
s.pdd.Age,
s.pdd.SittingId
})

Related

Get max Datetime that is Nullable

I am trying to getting the max enddate of a list object using a group by with the Id and ProductId. But I am getting a Nullable object must have a value." I have tried the HasValue but I get a runtime error? Am I doing this incorrect?
static void Main(string[] args)
{
try
{
List<Data> ListOfData = new List<Data>();
ListOfData.Add(new Data() { Id = 1, ProductId = 5, EndDate = null });
ListOfData.Add(new Data() { Id = 2, ProductId = 6, EndDate = null });
ListOfData.Add(new Data() { Id = 3, ProductId = 4, EndDate = DateTime.Now });
//var ListofUniqueData = ListOfData.GroupBy(r => new { r.Id, r.ProductId })
// .Select(g => g.OrderByDescending(r => r.EndDate.HasValue ? r.EndDate.Value : null ).First())
// .Select(i => new { i.Id, i.ProductId, i.EndDate.HasValue ? i.EndDate.Value : null })
// .ToList();
var ListofUniqueData = ListOfData.GroupBy(r => new { r.Id, r.ProductId })
.Select(g => g.OrderByDescending(r => r.EndDate.Value)
.First())
.Select(i => new { i.Id, i.ProductId, i.EndDate.Value })
.ToList();
}
catch ( Exception ex )
{
ex.ToString();
}
}
class Data
{
public int Id { get; set; }
public int ProductId { get; set; }
public DateTime? EndDate { get; set; }
}
You can use GetValueOrDefault to get the default value of the type if it's not assigned:
var ListofUniqueData = ListOfData.GroupBy(r => new {r.Id, r.ProductId})
.Select(g => g.OrderByDescending(r => r.EndDate.GetValueOrDefault()).First())
.Select(i => new {i.Id, i.ProductId, i.EndDate.GetValueOrDefault()})
.ToList();

Select a restricted subset of items based on child property

I'm just wondering if there's a better way to write this code, basically the source object contains a mix of items with a boolean property however the destination object has two lists which should contain the true/false items independently.
I've written it in Linq and it works just fine but it feels as though there's a better way. Any suggestions?
void Main()
{
var s = new ResponseObject()
{
Results = new List<GroupedObject>()
{
new GroupedObject()
{
Name = "List A",
List=new List<DetailObject>()
{
new DetailObject{ Name = "Allowed", AllowedAccess = true},
new DetailObject{ Name = "Restricted", AllowedAccess = false}
}
},
new GroupedObject()
{
Name = "List B",
List=new List<DetailObject>()
{
new DetailObject{ Name = "Allowed", AllowedAccess = true},
new DetailObject{ Name = "Restricted", AllowedAccess = false}
}
}
}
};
var d = new ResponseViewModel();
d.AllowedResults = FilterObjectsByAccess(s.Results, true);
d.RestrictedResults = FilterObjectsByAccess(s.Results, false);
// Other stuff
}
public IEnumerable<GroupedObject> FilterObjectsByAccess(IEnumerable<GroupedObject> source, bool allowAccess)
{
return source.Where(i => i.List.Any(c => c.AllowedAccess == allowAccess))
.Select(i => new GroupedObject()
{
Name = i.Name,
List = i.List.Where(c => c.AllowedAccess == allowAccess)
});
}
public class ResponseObject
{
public IEnumerable<GroupedObject> Results { get; set; }
}
public class ResponseViewModel
{
public IEnumerable<GroupedObject> AllowedResults { get; set; }
public IEnumerable<GroupedObject> RestrictedResults { get; set; }
}
public class GroupedObject
{
public string Name { get; set; }
public IEnumerable<DetailObject> List { get; set; }
}
public class DetailObject
{
public string Name { get; set; }
public bool AllowedAccess { get; set; }
}
One change that may be worth benchmarking would be changing:
public IEnumerable<GroupedObject> FilterObjectsByAccess(IEnumerable<GroupedObject> source, bool allowAccess)
{
return source.Where(i => i.List.Any(c => c.AllowedAccess == allowAccess))
.Select(i => new GroupedObject()
{
Name = i.Name,
List = i.List.Where(c => c.AllowedAccess == allowAccess)
});
}
to:
public IEnumerable<GroupedObject> FilterObjectsByAccess(IEnumerable<GroupedObject> source, bool allowAccess)
{
return source
.Select(i => new GroupedObject()
{
Name = i.Name,
List = i.List.Where(c => c.AllowedAccess == allowAccess).ToList() // `ToList` here is optional - it is a trade-off between RAM and CPU
})
.Where(z => z.List.Any());
}
Your original code, with the use of Any then Where would enumerate i.List twice. The above change would likely improve that.
Another approach, which would likely involve even higher memory consumption could be to switch to using ToLookup:
var d = new ResponseViewModel
{
AllowedResults =
FilterObjectsByAccess(s.Results)
.Select(z => new GroupedObject() { Name = z.Name, List = z.GroupedList[false] })
.Where(z => z.List.Any()),
RestrictedResults =
FilterObjectsByAccess(s.Results)
.Select(z => new GroupedObject() { Name = z.Name, List = z.GroupedList[true] })
.Where(z => z.List.Any())
};
// Other stuff
}
public List<SpecialGroupedObject> FilterObjectsByAccess(IEnumerable<GroupedObject> source)
{
return source.Select(i => new SpecialGroupedObject()
{
Name = i.Name,
GroupedList = i.List.ToLookup(c => c.AllowedAccess)
}).ToList();
}
I can suggest you to use ToDictionary() like this:
var result = new[] {true, false}.ToDictionary(k => k,
v =>
s.Results.Where(w => w.List.Any(x => x.AllowedAccess == v))
.Select(c => new GroupedObject {Name = c.Name, List = c.List.Where(l => l.AllowedAccess == v)}));
var allowedResults = result[true];
var restrictedResults = result[false];
Or this:
var result = s.Results
.SelectMany(c => c.List, (b, c) => new {b.Name, DObj = c})
.GroupBy(g => g.DObj.AllowedAccess)
.ToDictionary(k=> k.Key,
c =>
new {
c.Key,
List =
c.GroupBy(cg => cg.Name)
.Select(
x => new GroupedObject {Name = x.Key, List = x.Select(l => l.DObj).ToList()})
.ToList()
});

Split and group by using Linq

I have done the below which is working fine.
public StandardReportsModel GetStandardReportsModel(string adUser, string adPassword, IPrincipal user)
{
var myItems = getMyItems().Where(myItem => !string.IsNullOrEmpty(myItem.Description));
var categories = new List<string>();
var myItems = new List<MyModel>();
foreach (var myItem in myItems)
{
var myIndex = myItem.Description.IndexOf('*');
var category = myIndex != -1 ? myItem.Description.Substring(0, myIndex).ToUpper() : myItem.Description.ToUpper();
if (categories.IndexOf(category) == -1)
{
categories.Add(category);
}
myItems.Add(getMyItem(myItem, category));
}
categories.Sort();
return new StandardModel { Categories = categories, MyItems = myItems };
}
private MyModel getMyItem(MyItem myItem, string category)
{
var categoryIdentifierIndex = myItem.Description.LastIndexOf(Delimiters.CategoryDescriptionDelimiter);
var description = categoryIdentifierIndex != -1 ? myItem.Description.Substring(categoryIdentifierIndex + 1, (myItem.Description.Length - categoryIdentifierIndex + 1))) : myItem.Description;
return new MyModel{ Name = myItem.Name, Description = myItem.Description, Category = category };
}
public class StandardModel
{
public List<string> Categories { get; set; }
public List<MyModel> MyItems { get; set; }
}
Now I am trying to do the same with Linq and I have reached till below. From the obtained result I can get distinct of category and sort it. Is there a way by which it can be doen in a single query?
var result = myItems.Where(myItem => !string.IsNullOrEmpty(myItem.Description))
.Select(ci => new MyModel
{
Name = ci.Name,
Category = ci.Description.Split('*')[0],
Description = ci.Description.Split('*')[2]
}).ToList();
I want categories and their items. Probably I might have to use group by here.
Please suggest
Dictionary<string, List<MyModel>> result = myItems
.Where(myItem => !string.IsNullOrEmpty(myItem.Description))
.Select(ci => new MyModel
{
Name = ci.Name,
Category = ci.Description.Split('*')[0],
Description = ci.Description.Split('*')[2]
})
.GroupBy(e => e.Category)
.ToDictionary(e => e.Key, e => e.ToList());

LINQ Lambda Group By with Sum

Hi I can do this in method syntax but I'm trying to improve my lambda skills how can I do:
SELECT SUM([job_group_quota]) as 'SUM'
FROM [dbo].[tbl_job_session]
WHERE [job_group_job_number] = #jobnum
and [job_group_ID] like #sess
GROUP BY [job_group_job_number]
I've been messing around with it but can't get it right.
lnq.tbl_job_sessions.GroupBy(a => a.job_group_job_number == jnum)
.Select(b => new { b.job_group_quota}).Sum();
A general example:
query
.GroupBy(item => item.GroupKey)
.Select(group => group.Sum(item => item.Aggregate));
Few Group by Examples
public void GroupBy1()
{
var personList = dbEntities.People.GroupBy(m => m.PersonType).Select(m => new { PersonType = m.Key, Count = m.Count() });
}
public void GroupBy2()
{
var personList = dbEntities.People.GroupBy(m => new { m.PersonType, m.FirstName }).Select(m => new { PersonType = m.Key, Count = m.Count() });
}
public void GroupBy3()
{
var personList = dbEntities.People.Where(m => m.EmailPromotion != 0).GroupBy(m => new { m.PersonType, m.FirstName }).Select(m => new { PersonType = m.Key, Count = m.Count() });
}
public void GroupBy4()
{
var personList = dbEntities.People.GroupBy(m => new { m.PersonType, m.FirstName }).Where(m => m.Count() > 70).Select(m => new { PersonType = m.Key, Count = m.Count() });
}
public void GroupBy5()
{
var personList = dbEntities.People
.GroupBy(m =>
new
{
m.PersonType
}).Where(m => m.Count() > 70)
.Select(m =>
new
{
PersonType = m.Key,
Count = m.Count()
});
var list1 = dbEntities.People.
GroupBy(m => new { m.PersonType }).
Select(m =>
new
{
Type = m.Key,
Count = m.Count()
})
.Where(
m => m.Count > 70
&& m.Type.PersonType.Equals("EM")
|| m.Type.PersonType.Equals("GC"));
}
public void GroupBy6()
{
var list1 = dbEntities.People.
GroupBy(m => new { m.PersonType, m.EmailPromotion }).Select(m =>
new
{
Type = m.Key,
Count = m.Count()
})
.Where
(
m => m.Count > 70 && m.Type.EmailPromotion.Equals(0) &&
(
m.Type.PersonType.Equals("EM") ||
m.Type.PersonType.Equals("GC")
));
}
public void GroupBy7()
{
var list1 = dbEntities.People.
GroupBy(m => m.PersonType).
Select(c =>
new
{
Type = c.Key,
Total = c.Sum(p => p.BusinessEntityID)
});
}
public void GroupBy8()
{
var list1 = dbEntities.People.
GroupBy(m => m.PersonType).
Select(c =>
new
{
Type = c.Key,
Count = c.Count(),
Total = c.Sum(p => p.BusinessEntityID)
});
}
public void GroupBy9()
{
var list1 = dbEntities.People.
GroupBy(m => m.PersonType).
Select(c =>
new
{
Type = c.Key,
Max = c.Max(),
});
}
If you want to get a key-to-sum Dictionary result.
var allJobQuota = jobSessions.GroupBy(s => s.jobNumber)
.ToDictionary(g => g.Key, g => g.Sum(s => s.quota));
This example shows how to iterate the grouped values getting the key and totals, and how to get totals directly (like previous). Both using only lambda operator.
using System;
using System.Collections.Generic;
using System.Linq;
public class Person
{
public string Name { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public int SomeValue { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Person> data = GetPopulatedData();
var totals = data.GroupBy(x =>
new { x.Name, x.City, x.ZipCode }).Select(y =>
y.Sum(i => i.SomeValue));
var groupsForIterate = data.GroupBy(x =>
new { x.Name, x.City, x.ZipCode });
Console.WriteLine("Totals: ");
foreach (var total in totals)
{
Console.WriteLine(total);
}
Console.WriteLine("Categories: ");
foreach (var categ in groupsForIterate)
{
// You can refer to one field like this: categ.Key.Ciduad
Console.WriteLine("Group" + categ.Key);
Console.WriteLine(categ.Sum(x => x.SomeValue));
}
//Output:
//Totals:
//1
//2
//1
//Categories:
//Group{ Name = Mark, City = BCN, ZipCode = 00000 }
//1
//Group{ Name = Mark, City = BCN, ZipCode = 000000 }
//2
//Group{ Name = John, City = NYC, ZipCode = 000000 }
//1
}
private static List<Person> GetPopulatedData()
{
List<Person> datos = new List<Person>()
{
new Person(){Name="Mark", City = "BCN",
ZipCode = "00000", SomeValue = 1}, // group A
new Person(){Name="Mark", City = "BCN",
ZipCode = "000000", SomeValue = 1}, // group B
new Person(){Name="Mark", City = "BCN",
ZipCode = "000000", SomeValue = 1}, // group B
new Person(){Name="John", City = "NYC",
ZipCode = "000000", SomeValue = 1}, // group C
};
return datos;
}
}
Sum Ficha_Venda and Entrada from Movimento:
var query = from bd in db.Movimento
where (movimento.Data != null ? bd.Data == movimento.Data : bd.Data == movimento.Data)
&& (bd.Loja == Loja)
group bd by bd.Data into t
select new {entrada = t.Sum(bd=> bd.Entrada), ficha = t.Sum(bd=> bd.Ficha_Venda)};

Select Max value from sublist with LINQ

How to write a LINQ query that would return row of type "Value" with Max Date and Max value for that date. it should be the row where name = "Correct"
I've written a query at the end, and it working, just trying to find a correct way of doing this.
Thanks in advance
public class MeasurePoint
{
public int No { get; set; }
public string Weight { get; set; }
public List<Values> Vals { get; set; }
}
public class Values
{
public string Name { get; set; }
public int Val { get; set; }
public DateTime Date { get; set; }
}
public static class Test
{
public static void Calc()
{
var mps = new List<MeasurePoint>();
mps.Add(new MeasurePoint()
{
No = 1,
Vals = new List<Values>()
{
new Values(){Date = DateTime.Now.Date.AddDays(1), Name = "testas", Val = 1},
new Values(){Date = DateTime.Now.Date.AddDays(2), Name = "testas", Val = 5},
new Values(){Date = DateTime.Now.Date, Name = "testas", Val = 15}
}});
mps.Add(new MeasurePoint()
{
No = 2,
Vals = new List<Values>()
{
new Values(){Date = DateTime.Now.Date, Name = "testas", Val = 11},
new Values(){Date = DateTime.Now.Date.AddDays(2), Name = "Correct", Val = 55},
new Values(){Date = DateTime.Now.Date, Name = "testas", Val = 15}
}
});
mps.Add(new MeasurePoint()
{
No = 3,
Vals = new List<Values>()
{
new Values(){Date = DateTime.Now.Date.AddDays(1), Name = "testas", Val = 111},
new Values(){Date = DateTime.Now.Date.AddDays(2), Name = "testas", Val = 52},
new Values(){Date = DateTime.Now.Date, Name = "testas", Val = 15}
}
});
mps.Add(new MeasurePoint()
{
No = 4,
Vals = new List<Values>()
});
var x = mps.ElementAt(0).Vals.Union(mps.ElementAt(1).Vals).Union(mps.ElementAt(2).Vals);
var z = x.Where(p => p.Date == x.Max(d => d.Date)).MaxBy(t=>t.Val);
//One more way I've found
var ttt = mps.SelectMany(p => p.Vals).GroupBy(t=>t.Date).MaxBy(r=>r.Key).MaxBy(g=>g.Val);
}
var max = mps.SelectMany(x => x.Vals)
.Aggregate((a, x) => (x.Date > a.Date) ||
((x.Date == a.Date) && (x.Val > a.Val)) ? x : a);
try this
var result = mps.Where(m => m.Vals.Count > 0)
.SelectMany(m => m.Vals
.OrderByDescending(v => v.Date)
.Take(1), (m, v) => new {m.No, v.Date, v.Name, v.Val});
EDIT - this is a new version as issue has become more clear
var result = mps.Where(m => m.Vals.Count > 0)
.SelectMany(m => m.Vals)
.OrderByDescending(v => v.Date)
.ThenByDescending(v => v.Val).Take(1);
How can use call MaxBy() if it's a method of IObservable<T> meanwhile GroupBy() returns IEnumerable<T> ?

Categories

Resources