I want to use try-catch to check being divided by 0 in
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) /
(double)subList.Skip(idx - t + 1).First().Close
...but I don't know where to add try-catch. I try to add including the whole var newList =, but it is not allowed, since variable newList no longer exists later. So where is the proper position to add try-catch?
var newList = data.GroupBy(o => o.Date).Where(o => o.Key <= Beginday).OrderByDescending(o => o.Key).Take(Y).SelectMany(o => o).GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) =>
{
return new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = (idx < t - 1) ? 0 : new DescriptiveStatistics(subList.Skip(idx - t + 1).Take(t)
.Select(o =>
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) / (double)subList.Skip(idx - t + 1).First().Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
depends on what you're going to do in your catch - if you want newList to have a valid value even if the divisor is 0 then you should probably have your 0 check integrated into the main code flow rather than using exceptional flows.
However, to directly answer your question as written, explicity declare newList to a default value first, then reassign within a try/catch block (place the entirety of the code you've written inside the try, with the explicit default declaration before the try). Then newList will exist when you need to use it later.
If you want to catch everything then
try
{
var newList = data.GroupBy(o => o.Date).Where(o => o.Key <= Beginday).OrderByDescending(o => o.Key).Take(Y).SelectMany(o => o).GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) =>
{
return new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = (idx < t - 1) ? 0 : new DescriptiveStatistics(subList.Skip(idx - t + 1).Take(t)
.Select(o =>
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) / (double)subList.Skip(idx - t + 1).First().Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
}
catch(Exception ex)
{
//your error
}
You can certainly do this:
var newList = new[]
{
new { Symbol = "", Close = 0.0, Date = DateTime.Now, Vol = 0 }
}.Take(0).ToList();
try
{
var newList = data.GroupBy(o => o.Date).Where(o => o.Key <= Beginday).OrderByDescending(o => o.Key).Take(Y).SelectMany(o => o).GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) =>
{
return new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = (idx < t - 1) ? 0 : new DescriptiveStatistics(subList.Skip(idx - t + 1).Take(t)
.Select(o =>
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) / (double)subList.Skip(idx - t + 1).First().Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
}
catch (Exception ex)
{
}
So long as the names and types are the same in the two anonymous types then this works fine.
Related
var newList = data.GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) => new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
/*p = (idx < 1) ? null : subList.Skip(idx - 1)
.Take(2).Select(o => o.Close).ToList()*/,
Vol = (idx < 1) ? 0 : new DescriptiveStatistics
(subList.Skip(idx - 1).Take(2).Select(o => (double)o.Close/(double)
subList.ElementAt(idx - 1).Close).ToList()).StandardDeviation,
});
}
)
.SelectMany(x => x)
.ToList();
I want create a variable p = (idx < 1) ? null : subList.Skip(idx - 1).Take(2).Select(o => o.Close).ToList() with the same index idx of Vol but do not appear in the return just a temporary variable(but have to use the synchronous idx as Vol). So where to write down this p or how to change the syntax
You can hold a temp variable, just like you have done with subList although I dont have a test structure to build against something like this below should work.
var newList = data.GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) => { //return is a function not an object
var p = (idx < 1) ? null : subList.Skip(idx - 1).Take(2).Select(o => o.Close).ToList(); //your p
return new //this return returns the object definition
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = p == null ? 0 : new DescriptiveStatistics(subList.Skip(idx - 1).Take(2).Select(o => (double)o.Close / (double)subList.ElementAt(idx - 1).Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
I'm trying to output an anonymous type from a GroupJoin in LINQ but one query works and another one doesn't.
The only difference is in the first query the starting service is an in memory IGrouping (a member from a previous call to GroupBy) instead of a direct database query.
The error I'm getting is
Error 8 The type arguments for method 'System.Linq.Enumerable.GroupJoin(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable, System.Func, System.Func, System.Func,TResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. C:\Users\wbutt\Documents\Visual Studio 2013\Projects\ServiceGraphMonitor\Controllers\ServiceQueueController.cs 148 30 ServiceGraphMonitor
This is the query that doesn't work:
var result = index.GroupJoin(service.GroupBy(
s => new
{
h = s.orig_que_dt.Hour,
s = s.orig_que_dt.Minute / 15
}
), i => i, s => s.Key,
(i, s) => new
{
x = new DateTime(start_date.Year, start_date.Month, start_date.Day, i.h, i.m * 15, 0),
y = s.Count()
}
);
This one works:
var result = index.GroupJoin(db.t_svc_task_sta.Where(ts =>
ts.t_svc_task.orig_que_dt > start_date &&
ts.t_svc_task.orig_que_dt < end_date
).GroupBy(ts => new
{
h = ts.t_svc_task.orig_que_dt.Hour,
m = ts.t_svc_task.orig_que_dt.Minute / 15
}
), i => i, ts => ts.Key,
(i, ts) => new // DTO.ServiceReport()
{
time = new DateTime(start_date.Year, start_date.Month, start_date.Day, i.h, i.m * 15, 0).ToUniversalTime(),
queue_time = ts.Sum(t => t.Where(x => x.svc_task_sta_cd == 1 && x.sta_end_dt <= DateTime.Now).DefaultIfEmpty(new t_svc_task_sta() {sta_start_dt = DateTime.Today, sta_end_dt = DateTime.Today }).Average(x => (x.sta_end_dt - x.sta_start_dt).TotalSeconds)),
exec_time = ts.Sum(t => t.Where(x => x.svc_task_sta_cd == 2 && x.sta_end_dt <= DateTime.Now).DefaultIfEmpty(new t_svc_task_sta() {sta_start_dt = DateTime.Today, sta_end_dt = DateTime.Today }).Average(x => (x.sta_end_dt - x.sta_start_dt).TotalSeconds)),
volume = ts.Sum(t => t.Count(x => x.svc_task_sta_cd == 1))
}
);
I want to count some filtered data in List of objects (TSource), while processing it in result list (TResult). My method looks like:
int ratedUsersCount = 0;
return sourceList.
.GroupBy(x => x.UserId)
.Select(u => {
var count = u.Count();
if (count >= 10) ratedUsersCount ++;
return new ... //some new object with calculations
}
)
.OrderByDescending(_ => some field)
.ThenByDescending(_ => some other field)
.Take(20)
.Select((u, i) => {
u.Index = i + 1;
u.Rating = i / ratedUsersCount ;
return u;
};
);
So, does the variable ratedUsersCount use incorrectly?
How can I fix the issue?
Try splitting your code up, it will become much cleaner, easier to understand, and won't produce side effects from within LINQ.
var groupedUsers = sourceUsers.GroupBy(x => x.UserId);
var minimumCount = 10;
var ratedUserCount = grouperUsers.Count(x => x.Take(minimumCount + 1).Count() >= minimumCount);
var intermediateUsers = groupedUsers.Select(x => new { /* ... */ });
var filteredUsers = intermediateUsers.OrderByDescending(/* ... */).ThenByDescending(/* ... */).Take(20);
var finalUsers = filteredUsers.Select(/* ... */);
Note that this may be a little slower, since grouperUsers.Count(x => x.Count() >= 10) will enumerate the IEnumerable in order to apply the counting function.
I am looking for simple LINQ to solve this:
string[] breakups = new[]
{
"YQ:50/BF:50/YR:50",
"YQ:50/SR:50",
"YQ:50/BF:50/YR:50",
"XX:00 .... and so on"
};
// LINQ expression
string expectedResult = "YQ:150/BF:100/YR:100/SR:50";
My alternate solution as follows
public static string CalcRTBreakup(string pstrBreakup)
{
string lstrBreakup = pstrBreakup;
try
{
string[] lstrArrRB = lstrBreakup.Split('#');
string[] lstrArrBreakupSplit = new string[lstrBreakup.Split('#')[0].Split('|').Length];
for (int count = 0; count < lstrArrRB.Length; count++)
{
string[] lstrArrtemp = lstrArrRB[count].Split('|');
for (int countinner = 0; countinner < lstrArrtemp.Length; countinner++)
{
if (string.IsNullOrEmpty(lstrArrBreakupSplit[countinner]))
{
if (string.IsNullOrEmpty(lstrArrtemp[countinner]))
continue;
lstrArrBreakupSplit[countinner] = lstrArrtemp[countinner];
}
else
{
if (string.IsNullOrEmpty(lstrArrtemp[countinner]))
continue;
lstrArrBreakupSplit[countinner] += "/" + lstrArrtemp[countinner];
}
}
}
for (int count = 0; count < lstrArrBreakupSplit.Length; count++)
{
if (string.IsNullOrEmpty(lstrArrBreakupSplit[count]))
continue;
lstrArrBreakupSplit[count] = CalcRTBreakupDict(lstrArrBreakupSplit[count].TrimEnd('/')).TrimEnd('/');
}
lstrBreakup = string.Empty;
foreach (string strtemp in lstrArrBreakupSplit)
{
lstrBreakup += strtemp + '|';
}
return lstrBreakup;
}
catch (Exception)
{
return "";
}
}
public static string CalcRTBreakupDict(string pstrBreakup)
{
string lstrBreakup = pstrBreakup;
Dictionary<string, double> ldictDreakup = new Dictionary<string, double>();
try
{
lstrBreakup = lstrBreakup.TrimEnd('/').Trim();
string[] lstrArrBreakup = lstrBreakup.Split('/');
foreach (string strBr in lstrArrBreakup)
{
string[] lstrBreakupCode = strBr.Split(':');
if (!ldictDreakup.Keys.Contains(lstrBreakupCode[0]))
{
double lintTemp = 0; double.TryParse(lstrBreakupCode[1], out lintTemp);
ldictDreakup.Add(lstrBreakupCode[0], lintTemp);
}
else
{
double lintTemp = 0; double.TryParse(lstrBreakupCode[1], out lintTemp);
lintTemp = lintTemp + ldictDreakup[lstrBreakupCode[0]];
ldictDreakup.Remove(lstrBreakupCode[0]);
ldictDreakup.Add(lstrBreakupCode[0], lintTemp);
}
}
lstrBreakup = string.Empty;
foreach (string dictKey in ldictDreakup.Keys)
{
lstrBreakup += dictKey + ":" + ldictDreakup[dictKey] + "/";
}
return lstrBreakup;
}
catch (Exception)
{
return pstrBreakup;
}
}
string[] breakups =
{
"YQ:50/BF:50/YR:50",
"YQ:50/SR:50",
"YQ:50/BF:50/YR:50",
"XX:00"
};
var groups = from line in breakups // these are our items in the array
from item in line.Split('/') // each one will be split up at '/'
let pair = item.Split(':') // each pair is split at ':'
let key = pair[0] // our key is the first item...
let value = int.Parse(pair[1]) // and the value is the second
group value by key // let's group by key
into singleGroup
let sum = singleGroup.Sum() // and build each group's sum
where sum > 0 // filter out everything <= 0
select singleGroup.Key + ":" + sum; // and build the string
var result = string.Join("/", groups);
If you don't need an ordering by value, you can simply do
var res = string.Join("/", breakups
.SelectMany(m => m.Split('/'))
.Select(x => x.Split(':'))
.GroupBy(m => m[0])
.Select(m => string.Format("{0}:{1}", m.Key, m.Sum(g => Int32.Parse(g[1])))));
if you need ordering
var res = string.Join("/", breakups
.SelectMany(m => m.Split('/'))
.Select(x => x.Split(':'))
.GroupBy(m => m[0])
.Select(m => new
{
key = m.Key,
val = m.Sum(g => Int32.Parse(g[1]))
})
.OrderByDescending(m => m.val)
.Select(m => string.Format("{0}:{1}", m.key, m.val)));
var sums = breakups.SelectMany(breakup => breakup.Split('/'))
.Select(s => new { Code = s.Substring(0, 2), Value = int.Parse(s.Substring(2)) })
.GroupBy(pair => pair.Code)
.Select(group => string.Format("{0}/{1}", group.Key, group.Sum(x => x.Value)));
string result = string.Join("/", sums);
The code may contain syntax errors, cause I've not tested it.
Looking at the result I am assuming you add the values after the semicolon where the label before the semicolon match.
It can be treated as a little fun quiz, maybe more suited to another stackexchange site, but anyway.
This can be achieved with a simple (but not very short) linq expression:
breakups
.Select(c => c.Split('/'))
.SelectMany(c => c)
.Select(c => new
{
Label = c.Split(':')[0],
Value = Convert.ToInt32(c.Split(':')[1])
})
.GroupBy(c => c.Label)
.Select(c => new
{
Label = c.Key,
Value = c.Sum(x => x.Value)
})
.OrderByDescending(c => c.Value)
.Select(c => c.Label + ":" + c.Value)
.Aggregate((s1,s2) => s1 + "/" + s2)
I have an array of 2000 strings. The strings are: "art", "economy", "sport" and "politic". I want to group each 500 elements and get their counts
Could anyone help please?
Another solution:
var count = 0;
var dictionaries =
strings.GroupBy(s => count++ / 500)
.Select(g => g.Distinct().ToDictionary(k => k, k => g.Count(s => s == k)))
.ToList();
This will create a List<Dictionary<string, int>>. Each dictionary represents a tally of 500 elements (or possibly less for the last dictionary), where the keys are strings and the values are the number of occurrences of the string among the 500 elements the dictionary represents.
There is no requirement to hardcode all the possible values that may be encountered.
For the maximum possible performance you can also use this version:
var count = 0;
var dictionaries =
strings.GroupBy(s => count++ / 500)
.Select(g => g.Aggregate(
new Dictionary<string, int>(),
(d, w) => { d[w] = (d.ContainsKey(w) ? d[w] + 1 : 1); return d; })
)
.ToList();
This version iterates over each element in your source array exactly once. The output is in the same format as the first version.
var result = strings.Select((s, i) => new { s, i })
.GroupBy(x => x.i / 500)
.Select(x => x.GroupBy(y => y.s)
.Select(z => new {
Name=z.Key,
Count=z.Count()
}).ToList())
.ToList();
Try
var grouping = Enumerable.Range(0,2000)
.Select(i => i / 500)
.Zip(Strings, (i,s) => new { Group = i, Str = s})
.GroupBy(anon => anon.Group,
anon => anon.Str,
(key,g) => new
{
Key = key,
Art = g.Count(str => str == "art"),
Economy = g.Count(str => str == "economy"),
Politic = g.Count(str => str == "politic"),
Sport= g.Count(str => str == "sport")
});
foreach(anon in grouping)
{
//textbox logic OP will have to change to suit
TextBox1.WriteLine(String.Format("Group: {0}", anon.Key));
TextBox1.WriteLine(String.Format("Art: {0}",anon.Art));
TextBox1.WriteLine(String.Format("Economy: {0}",anon.Economy ));
TextBox1.WriteLine(String.Format("Politic: {0}",anon.Politic ));
TextBox1.WriteLine(String.Format("Sport: {0}",anon.Sport));
}
Alternatively (as per Snowbear)
var grouping = Strings.Select((s,i) => new { Group = i / 500, Str = s})
.GroupBy(anon => anon.Group,
anon => anon.Str,
(key,g) => new
{
Key = key,
Art = g.Count(str => str == "art"),
Economy = g.Count(str => str == "economy"),
Politic = g.Count(str => str == "politic"),
Sport= g.Count(str => str == "sport")
});
foreach(anon in grouping)
{
//textbox logic OP will have to change to suit
TextBox1.WriteLine(String.Format("Group: {0}",anon.Key + 1));
TextBox1.WriteLine(String.Format("Art: {0}",anon.Art));
TextBox1.WriteLine(String.Format("Economy: {0}",anon.Economy ));
TextBox1.WriteLine(String.Format("Politic: {0}",anon.Politic ));
TextBox1.WriteLine(String.Format("Sport: {0}",anon.Sport));
}
int CountElementsInGroup = 500;
//from 500 to 1000
int NumberGroup = 2;
string[] GroupTypes = new string[4] { "art", "economy", "sport", "politic" };
//Fill example array
string[] arr = new string[2000];
Random rand = new Random();
for (int i = 0; i < arr.Length;i++ )
arr[i] = GroupTypes[rand.Next(0, 3)];
var res = (from p in arr.Skip((NumberGroup - 1) * CountElementsInGroup).Take(CountElementsInGroup)
group p by p into g
select new GroupCountClass { GroupName = g.Key, GroupCount = g.Count() });
textBox1.Text = "";
foreach (GroupCountClass c in res)
{
textBox1.Text += String.Format("GroupName:{0} Count:{1};",c.GroupName,c.GroupCount);
}