C# , MVC , EnityFramework , How to processing data - c#

I have this data
I would to convert Day to English value
for example :
"السبت" = "saturday"
"الاحد" = "sunday"
this code :
[HttpGet]
public JsonResult GetTime()
{
var data = _db.CourseTimes
.GroupBy(c => c.Day)
.ToDictionary(g => g.Key, v => v.Select(c => new { start = TimeSpan.FromHours(c.StartTime)
.ToString("hh':'mm"), stop = TimeSpan.FromHours(c.EndTime).ToString("hh':'mm") }));
return Json(data, JsonRequestBehavior.AllowGet);
}
return this :
{"الاحد":[{"start":"01:00","stop":"02:00"},{"start":"01:00","stop":"02:00"},{"start":"14:00","stop":"20:00"}],"السبت":[{"start":"01:00","stop":"02:00"},{"start":"05:00","stop":"08:00"},{"start":"07:00","stop":"06:00"}]}
I want it to return this:

OK, here is an implementation of how to do it:
[HttpGet]
public JsonResult GetTime()
{
var english_names = (new CultureInfo("en-US")).DateTimeFormat.DayNames
.Select((v, i) => new { Key = i, Value = v })
.ToDictionary(o => o.Key, o => o.Value);
var arabic_names = (new CultureInfo("ar-EG")).DateTimeFormat.DayNames
.Select((v, i) => new { Key = i, Value = v })
.ToDictionary(o => o.Key, o => o.Value);
var data = _db.CourseTimes
.GroupBy(c => c.Day)
.ToDictionary(g => english_names.FirstOrDefault(p => p.Key == arabic_names.FirstOrDefault(a => a.Value == g.Key).Key).Value, v => v.Select(c => new
{
start = TimeSpan.FromHours(c.StartTime).ToString("hh':'mm"),
stop = TimeSpan.FromHours(c.EndTime).ToString("hh':'mm")
}).ToList());
return Json(data, JsonRequestBehavior.AllowGet);
}
Basically, you just need to create two lists of names for each language and get the index of the english one for the arabic name, which is found on the second list.

try using CultureInfo, or you must mapping the word into table or static list, and compare that word...

Related

How to sort result based on hit score in NEST elastic search with Highlights

I am using NEST(c#) to communicate with Elasticsearch, version 1.7.3
I am passing a string and trying to multi match fields in that string.
I am getting the Highlights to figure how many fields matched in the string.
Returing the results from the Hits.Select.
But the issue is, sometimes the most matched fields in the Highlights does not appear at the top of the list from Hits.Select.
Anything to set this right??
var result = this.client.Search<PInfo>(s => s
.Take(20)
.TrackScores(true)
.Query(q => q
.MultiMatch(m => m
.Type(TextQueryType.CrossFields)
.OnFieldsWithBoost(b => b
.Add(f => f.A, 1.0)
.Add(f => f.B, 1.0)
.Add(f => f.C, 1.0)
)
.Operator(Operator.Or)
.Query(text)
))
.Highlight( h => h
//.PreTags("<b>")
//.PostTags("</b>")
.OnFields(
fk => fk.OnField( a => a.A),
fk => fk.OnField( a => a.B),
fk => fk.OnField( a => a.C)
)
)
.Sort(sort => sort.OnField("_score").Descending())
);
string value = result.ConnectionStatus.ToString();
return result
.Hits
.Select(c => new PInfo
{
Id = c.Source.Id,
A = c.Source.A,
B = c.Source.B,
C = c.Source.C,
IndexedOn = c.Source.IndexedOn,
Highlights = c.Highlights // returning the highlights too from here
})
.ToList();
This should get the desired result.
return result
.Hits
.Select(c => new PatientInfo
{
Id = c.Source.Id,
Patient_Num = c.Source.Patient_Num,
First_Name = c.Source.First_Name,
Last_Name = c.Source.Last_Name,
Full_Name = c.Source.Full_Name,
Address = c.Source.Address,
City = c.Source.City,
State = c.Source.State,
Zip = c.Source.Zip,
Relation_Code = c.Source.Relation_Code,
DOB = c.Source.DOB,
Sex = c.Source.Sex,
IndexedOn = c.Source.IndexedOn,
Highlights = c.Highlights
})
.OrderByDescending(t => t.Highlights.Count).ToList();

The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities

var residenceRep =
ctx.ShiftEmployees
.Include(s => s.UserData.NAME)
.Include(s => s.ResidenceShift.shiftName)
.Join(ctx.calc,
sh => new { sh.empNum, sh.dayDate },
o => new { empNum = o.emp_num, dayDate = o.trans_date },
(sh, o) => new { sh, o })
.Where(s => s.sh.recordId == recordId && s.o.day_flag.Contains("R1"))
.OrderBy(r => r.sh.dayDate)
.Select(r => new
{
dayDate = r.sh.dayDate,
empNum = r.sh.empNum,
empName = r.sh.UserData.NAME,
shiftId = r.sh.shiftId,
shiftName = r.sh.ResidenceShift.shiftName,
recordId,
dayState = r.o.day_desc.Split('[', ']')[1]
}).ToList();
I get an exception :
The LINQ expression node type 'ArrayIndex' is not supported in LINQ to
Entities
How i could find an alternative to Split('[', ']')[1] in this query
You must commit the query and do the split after loading the data:
var residenceRep =
ctx.ShiftEmployees
.Include(s => s.UserData.NAME)
.Include(s => s.ResidenceShift.shiftName)
.Join(ctx.calc,
sh => new { sh.empNum, sh.dayDate },
o => new { empNum = o.emp_num, dayDate = o.trans_date },
(sh, o) => new { sh, o })
.Where(s => s.sh.recordId == recordId && s.o.day_flag.Contains("R1"))
.OrderBy(r => r.sh.dayDate)
.Select(r => new
{
dayDate = r.sh.dayDate,
empNum = r.sh.empNum,
empName = r.sh.UserData.NAME,
shiftId = r.sh.shiftId,
shiftName = r.sh.ResidenceShift.shiftName,
recordId = r.sh.recordId,
dayState = r.o.day_desc,
})
.ToList()//Here we commit the query and load data
.Select(x=> {
var parts = x.dayState.Split('[', ']');
return new {
x.dayDate,
x.empNum,
x.empName,
x.shiftId,
x.shiftName,
x.recordId,
dayState = parts.Length > 1 ?parts[1]:"",
};
})
.ToList();
I had this Issue and the approach that I've chose was that get all element I wanted and save them into a List and then filter the actual data on that list.
I know this is not the best answer but it worked for me.

Append index number to duplicated string value in a list - by using Lambda

I have a IList<string>() which holds some string values, and there could be duplicated items in the list. What I want is to append a index number to end of the string to eliminate the duplication.
For example, I have these values in my list: StringA, StringB, StringC, StringA, StringA, StringB. And I want the result looks like: StringA1, StringB1, StringC, StringA2, StringA3, StringB2. I need to retain the original order in list.
Is there a way I can just use one Lambda expression?
You are looking for something like this:
yourList.GroupBy(x => x)
.SelectMany(g => g.Select((x,idx) => g.Count() == 1 ? x : x + idx))
.ToList();
Edit: If the element order matters, here is another solution:
var counts = yourList.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
var values = counts.ToDictionary(x => x.Key, x => 0);
var list = yourList.Select(x => counts[x] > 1 ? x + ++values[x] : x).ToList();
You can do:
List<string> list = new List<string> { "StringA", "StringB", "StringC", "StringA", "StringA", "StringB" };
var newList =
list.Select((r, i) => new { Value = r, Index = i })
.GroupBy(r => r.Value)
.Select(grp => grp.Count() > 1 ?
grp.Select((subItem, i) => new
{
Value = subItem.Value + (i + 1),
OriginalIndex = subItem.Index
})
: grp.Select(subItem => new
{
Value = subItem.Value,
OriginalIndex = subItem.Index
}))
.SelectMany(r => r)
.OrderBy(r => r.OriginalIndex)
.Select(r => r.Value)
.ToList();
and you will get:
StringA1,StringB1,StringC,StringA2,StringA3,StringB2
If you don't want to preserve order then you can do:
var newList = list.GroupBy(r => r)
.Select(grp => grp.Count() > 1 ?
grp.Select((subItem, i) => subItem + (i + 1))
: grp.Select(subItem => subItem))
.SelectMany(r => r)
.ToList();
This uses some lambda expressions and linq to do it, maintaining the order but I'd suggested a function with a foreach loop and yield return would be better.
var result = list.Aggregate(
new List<KeyValuePair<string, int>>(),
(cache, s) =>
{
var last = cache.Reverse().FirstOrDefault(p => p.Key == s);
if (last == null)
{
cache.Add(new KeyValuePair<string, int>(s, 0));
}
else
{
if (last.Value = 0)
{
last.Value = 1;
}
cache.Add(new KeyValuePair<string, int>(s, last.Value + 1));
}
return cache;
},
cache => cache.Select(p => p.Value == 0 ?
p.Key :
p.Key + p.Value.ToString()));

Linq groupby performance issue

in a mvc project i am using this method. However, when the database getting bigger and bigger, it is being very slow . How can i solve that ?
private List<SelectListItem> getDates() {
var db = new _Entities();
var list = new List<SelectListItem>();
var date = db.Location
.GroupBy(k => EntityFunctions.TruncateTime(k.DateServer))
.ToList();
//var date = db.Location.Select(m => m.DateService).Distinct();
foreach (var x in date)
{
list.Add(
new SelectListItem
{
Value = x.FirstOrDefault().DateServer.Date.ToShortDateString(),
Text = x.FirstOrDefault().DateServer.ToShortDateString()
} );
}
return list;
}
You should not create a list and a loop but use the database:
return db.Location.GroupBy(k => EntityFunctions.TruncateTime(k.DateServer))
.Select(group => new { group, first = group.First() })
.Select(x => new SelectListItem {
Value = x.first.DateServer.Date.ToShortDateString(),
Text = x.first.DateServer.ToShortDateString()
})
.ToList();
Since you are grouping by date the text and the value are the same, so it could be simplified:
return db.Location.GroupBy(k => EntityFunctions.TruncateTime(k.DateServer))
.Select(g => new SelectListItem { Value = g.Key.ToShortDateString(), Value = g.Key.ToShortDateString() })
.ToList();

How to group dictionary by dateTime and do a sum on int

I have this code :
var tradeReqsBySegment = segGroups.Join(pPeriods, s => s.MarketSegmentId, p => p.EntityId, (s, p) => new
{
SegmentCode = s.SegmentCode, // string
Time = p.StartLocal, // datetime
TradeRequirement = p.Volume // double
})
.GroupBy(s => s.SegmentCode)
.ToDictionary(g => g.Key, g => g.ToDictionary(i => i.Time, i=>i.TradeRequirement));
I would like the g.ToDictionary(i => i.Time, i=>i.TradeRequirement)) to be grouped by time, and the TradeRequirement to be summed up or averaged. How do I approach this?
Also, is it possible to group the time by month by month basis, like get :
Time - TradeReq
01/2013 - 500
02/2013 - 234
...
g.GroupBy(gr => new DateTime(gr.Time.Year, gr.Time.Month, 1))
.ToDictionary(i => i.Key, i => i.Sum(s => s.TradeRequirement));
You can get both: Sum and Average at the same time, using anonymous type:
var tradeReqsBySegment = segGroups.Join(pPeriods, s => s.MarketSegmentId, p => p.EntityId, (s, p) => new
{
SegmentCode = s.SegmentCode, // string
Time = p.StartLocal, // datetime
TradeRequirement = p.Volume // double
})
.GroupBy(s => s.SegmentCode)
.ToDictionary(g => g.Key,
g => g.GroupBy(gr => new DateTime(gr.Time.Year, gr.Time.Month, 1))
.ToDictionary(gr => gr.Key.ToString("MM/yyyy"),
gr => new {
Sum = gr.Sum(s => s.TradeRequirement),
Avg = gr.Average(s => s.TradeRequirement)
}));

Categories