Query multiple tables and send query to Dictionary - c#

I'm trying to query multiple table and save the query as a global dictionary for further processing. I've tried the following, but instead of values I get the class name in the dictionary. Please take a look and show me what's wrong and where to read up more on todictionary queries?
public class linqtosql
{
public Dictionary<int, MC_VARIABLES> dctMC = new Dictionary<int, MC_VARIABLES>();
public class MC_VARIABLES
{
public int ID { get; set; }
public int UDLY_LAST { get; set; }
public int STRIKE { get; set; }
public decimal SKEW_A { get; set; }
public decimal SKEW_B { get; set; }
public double SKEW_C { get; set; }
}
public void GET_DATA()
{
var qryBOOK = from B in Globals.DATA.BOOKs
from O in Globals.DATA.OPTIONs
from U in Globals.DATA.UDLies
from S in Globals.DATA.SKEWs
where B.CONTRACT == O.CONTRACT
where O.UDLY_SYMBOL == U.UDLY_SYMBOL
where O.CONTRACT == S.CONTRACT
select new MC_VARIABLES
{ ID = B.ID, STRIKE = (int)B.STRIKE, SKEW_A = (decimal)S.SKEW_A };
dctMC = qryBOOK.ToDictionary(x => x.ID, x => x);
foreach (KeyValuePair<int, MC_VARIABLES> KVP in dctMC)
{
var key = KVP.Key;
var item = KVP.Value.SKEW_A;
}
}
}

it should be x => x instead of x => MC_VARIABLES, x is of type MC_VARIABLES in this case.
qryBOOK.ToDictionary(x => x.ID, x => x)

Related

Find all duplicates in a list in C#

I have a Custom class shown below
internal class RecurringClusterModel
{
public int? From { get; set; }
public int? To { get; set; }
public string REC_Cluster_1 { get; set; }
public string REC_Cluster_2 { get; set; }
public string REC_Cluster_3 { get; set; }
public string REC_Cluster_4 { get; set; }
public string REC_Cluster_5 { get; set; }
public string REC_Cluster_6 { get; set; }
public string REC_Cluster_7 { get; set; }
public string REC_Cluster_8 { get; set; }
public string REC_Cluster_9 { get; set; }
public string REC_Cluster_10 { get; set; }
I have a List of this class
List<RecurringClusterModel> recurringRecords = new List<RecurringClusterModel>();
The data can be in the below format
recurringRecords[0].REC_Cluster_1 = "USA";
recurringRecords[0].REC_Cluster_2 = "UK";
recurringRecords[0].REC_Cluster_3 = "India";
recurringRecords[0].REC_Cluster_4 = "France";
recurringRecords[0].REC_Cluster_5 = "China";
recurringRecords[1].REC_Cluster_1 = "France";
recurringRecords[1].REC_Cluster_2 = "Germany";
recurringRecords[1].REC_Cluster_3 = "Canada";
recurringRecords[1].REC_Cluster_4 = "Russia";
recurringRecords[1].REC_Cluster_5 = "India";
....
I want to find the duplicate records between all the Cluster properties..This is just a subset I have 50 properties till REC_Cluster_50. I want to find out which countries are getting duplicated between the 50 cluster properties of the list.
So in this case India and France are getting duplicated. I can group by individual property and then find out the duplicate by getting the count but then I d have to do it for all the 50 Rec_Clusters property. Not sure if there is a better way of doing it.
Thanks
Since you want to capture the From and To, I suggest you structure your class like this:
internal class RecurringClusterModel
{
public int? From { get; set; }
public int? To { get; set; }
public IEnumerable<string> REC_Clusters { get; set; }
}
Then you can search for duplicates:
var dupes = recs
.Select(r => new
{
r.From,
r.To,
DuplicateClusters = r.REC_Clusters.GroupBy(c => c)
.Where(g => g.Count() > 1) // duplicates
.SelectMany(g => g) // flatten it back
.ToArray() // indexed
})
.Where(r => r.DuplicateClusters.Any()) //only interested in clusters with duplicates
.ToArray();
EDIT
If you want all duplicates, then it will be:
var allDupes = recs.SelectMany(r => r.REC_Clusters)
.Select(r => r.GroupBy(c => c)
.Where(g => g.Count() > 1)
.SelectMany(g => g))
.Where(r => r.Any()).ToArray();
But now you lose track of the From/To
I would add an enumerable to your class that iterates over all properties of that class:
internal class RecurringClusterModel
{
public string REC_Cluster_1 { get; set; }
public string REC_Cluster_2 { get; set; }
public string REC_Cluster_3 { get; set; }
public IEnumerable<string> Clusters => GetAllClusters();
private IEnumerable<string> GetAllClusters()
{
if (!string.IsNullOrEmpty(REC_Cluster_1))
yield return REC_Cluster_1;
if (!string.IsNullOrEmpty(REC_Cluster_2))
yield return REC_Cluster_2;
if (!string.IsNullOrEmpty(REC_Cluster_3))
yield return REC_Cluster_3;
}
}
With this you can flatten the list to the individual clusters and then group by. If you need the original object back again, you have to provide it while flattening. Here is an example:
var clusters = Enumerable
.Range(1, 10)
.Select(_ => new RecurringClusterModel
{
REC_Cluster_1 = _Locations[_Random.Next(_Locations.Count)],
REC_Cluster_2 = _Locations[_Random.Next(_Locations.Count)],
REC_Cluster_3 = _Locations[_Random.Next(_Locations.Count)],
})
.ToList();
var dictionary = clusters
// Flatten the list and preserve original object
.SelectMany(model => model.Clusters.Select(cluster => (cluster, model)))
// Group by flattened value and put original object into each group
.GroupBy(node => node.cluster, node => node.model)
// Take only groups with more than one element (duplicates)
.Where(group => group.Skip(1).Any())
// Depending on further processing you could put the groups into a dictionary.
.ToDictionary(group => group.Key, group => group.ToList());
foreach (var cluster in dictionary)
{
Console.WriteLine(cluster.Key);
foreach (var item in cluster.Value)
{
Console.WriteLine(" " + String.Join(", ", item.Clusters));
}
}

How do I use LINQ to group & project objects, based on a member dictionary key?

I have a List<Predictions> that I would like to project onto a List<List<PredictionObj>>. These two classes are defined as follows:
public Predictions
{
public Dictionary<string, double> PredictedMetrics { get; private set; }
public DateTime PredictionTimeStamp { get; set; }
public Predictions()
{
PredictedMetrics = new Dictionary<string, double>();
}
}
public class PredictionObj
{
public string PredictedMetricName { get; set; }
public double PredictedMetricValue { get; set; }
public DateTime PredictionTimeStamp { get; set; }
}
For context, each Predictions object in the List<Predictions> list contains a collection (PredictedMetrics) of predicted values for a set of metrics, which were made at PredictionTimeStamp. I'd like to separate each of those metrics into their own list, such that there will be one list (List<PredictionObj>) for every unique PredictedMetrics key in the list. (PredictedMetricName will map to the dictionary's key, PredictedMetricValue will map to the dictionary's value). I'd like to store all of these lists in one List<List<PredictionObj>> list.
Is there a way to accomplish this using LINQ extension methods?
You can copy/paste the source below into LINQPad as an example. I'm looking for LINQ that will accomplish what GenerateSeperateMetricLists is doing:
void Main()
{
DateTime currTime = DateTime.UtcNow;
List<Predictions> records = new List<Predictions>();
Predictions record1 = new Predictions();
record1.PredictedMetrics.Add("metric1", 2.2d);
record1.PredictedMetrics.Add("metric2", 0.2d);
record1.PredictionTimeStamp = currTime;
records.Add(record1);
Predictions record2 = new Predictions();
record2.PredictedMetrics.Add("metric1", 1.2d);
record2.PredictedMetrics.Add("metric2", 0.1d);
record2.PredictionTimeStamp = currTime.AddMinutes(1);
records.Add(record2);
Predictions record3 = new Predictions();
record3.PredictedMetrics.Add("metric1", 3.2d);
record3.PredictedMetrics.Add("metric2", 0.3d);
record3.PredictionTimeStamp = currTime.AddMinutes(2);
records.Add(record3);
Predictions record4 = new Predictions();
record4.PredictedMetrics.Add("metric1", 4.2d);
record4.PredictedMetrics.Add("metric2", 0.4d);
record4.PredictionTimeStamp = currTime.AddMinutes(3);
records.Add(record4);
//What's the LINQ that could replace this method?
GenerateSeperateMetricLists(records).Dump();
}
private static List<List<PredictionObj>> GenerateSeperateMetricLists(List<Predictions> predictionRecords)
{
var predictionMetricLists = new List<List<PredictionObj>>();
foreach (Predictions forecastRecord in predictionRecords)
{
foreach (KeyValuePair<string, double> prediction in forecastRecord.PredictedMetrics)
{
PredictionObj predictionMetric = new PredictionObj
{
PredictedMetricName = prediction.Key,
PredictedMetricValue = prediction.Value,
PredictionTimeStamp = forecastRecord.PredictionTimeStamp
};
var metricList = predictionMetricLists.Where(x => x.First().PredictedMetricName == prediction.Key);
if (metricList.Count() == 0)
{
predictionMetricLists.Add(new List<PredictionObj> {predictionMetric});
}
else
{
metricList.First().Add(predictionMetric);
}
}
}
return predictionMetricLists;
}
private class Predictions
{
public Dictionary<string, double> PredictedMetrics { get; private set; }
public DateTime PredictionTimeStamp { get; set; }
public Predictions()
{
PredictedMetrics = new Dictionary<string, double>();
}
}
private class PredictionObj
{
public string PredictedMetricName { get; set; }
public double PredictedMetricValue { get; set; }
public DateTime PredictionTimeStamp { get; set; }
}
You should first flatten the data into a list of PredictionObj:
var flatList = records
.SelectMany(r => r.PredictedMetrics.Select(p => new PredictionObj
{
PredictedMetricName = p.Key,
PredictedMetricValue = p.Value,
PredictionTimeStamp = r.PredictionTimeStamp
}));
This produces a flat sequence of PredictionObj objects. Now you can group them by PredictedMetricName:
flatList.GroupBy(x => x.PredictedMetricName).Dump();
The query syntax equivalent, in one statement:
(
from r in records
from p in r.PredictedMetrics
select new PredictionObj
{
PredictedMetricName = p.Key,
PredictedMetricValue = p.Value,
PredictionTimeStamp = r.PredictionTimeStamp
} into flatList
group flatList by flatList.PredictedMetricName into fg
select fg
).Dump();
You just need to take each Prediction and project it into a List<PredictionObj> and then convert those into a List<Prediction>:
var ans = records.SelectMany(p => p.PredictedMetrics.Select(pm => new PredictionObj { PredictedMetricName = pm.Key, PredictedMetricValue = pm.Value, PredictionTimeStamp = p.PredictionTimeStamp }))
.GroupBy(p => p.PredictedMetricName)
.Select(g => g.ToList())
.ToList();
Updated for change in OP.

LINQ GroupBy return dictionary with given objects as value

I have an IEnumerable<ValueObj> object with multiple valid ValueObj objects in it. I would like to group those objects by Id and receive Dictionary<Guid, IEnumerable<ValueObj>> where the Key is Id from ValueObj, and Value is just unchanged ValueObj.
public class ValueObj
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public double Result { get; set; }
}
I've tried to mess with Linq GroupBy but with no success
IEnumerable<ValueObj> persons = ...;
var results = persons.GroupBy(
p => p.Id,
p => p,
(key, g) => new { PersonId = key, Cars = g.ToList() });
Try this:
IEnumerable<ValueObj> col = ...;
var dict = col.GroupBy(x => x.Id).ToDictionary(x => x.Key, x => x.ToList());

Sorting and Updating a Generic List of Object based on a Sub Object

I have the following objects:
public class TestResult
{
public string SectionName { get; set; }
public int Score { get; set; }
public int MaxSectionScore { get; set; }
public bool IsPartialScore { get; set; }
public string Name { get; set; }
public int NumberOfAttempts { get; set; }
}
public class TestResultGroup
{
public TestResultGroup()
{
Results = new List<TestResult>();
Sections = new List<string>();
}
public List<TestResult> Results { get; set; }
public List<string> Sections { get; set; }
public string Name { get; set; }
public int Rank { get; set; }
}
So, a TestResultGroup can have any number of results of type TestResult. These test results only differ by their SectionName.
I have a List<TestResultGroup> which I need to sort into descending order based on a score in the Results property, but only when Results has an item whos SectionName = "MeanScore" (if it doesnt have this section we can assume a score of -1). How would I go about ordering the list? Ideally I would also like to apply the result of this ordering to the Rank property.
Many Thanks
List<TestResultGroup> groups = ...
// group test result groups by the same score and sort
var sameScoreGroups = groups.GroupBy(
gr =>
{
var meanResult = gr.Results.FirstOrDefault(res => res.SectionName == "MeanScore");
return meanResult != null ? meanResult.Score : -1;
})
.OrderByDescending(gr => gr.Key);
int rank = 1;
foreach (var sameScoreGroup in sameScoreGroups)
{
foreach (var group in sameScoreGroup)
{
group.Rank = rank;
}
rank++;
}
// to obtain sorted groups:
var sortedGroups = groups.OrderByDescending(gr => gr.Rank).ToArray();
Or even write one expression with a side effect:
List<TestResultGroup> groups = ...
int rank = 1;
var sortedGroups = groups
.GroupBy(
gr =>
{
var meanResult = gr.Results.FirstOrDefault(res => res.SectionName == "MeanScore");
return meanResult != null ? meanResult.Score : -1;
})
.OrderByDescending(grouping => grouping.Key)
.SelectMany(grouping =>
{
int groupRank = rank++;
foreach (var group in grouping)
{
group.Rank = groupRank;
}
return grouping;
})
.ToArray(); // or ToList

How to count parent's property with linq

I have 2 object collections looking like this
public class Meter
{
public string UID { get; set; }
public string NR { get; set; }
public List<GMSData> data { get; set; }
}
public class GSMData : Meter
{
public DateTime TimeStamp { get; set; }
public int CellID { get; set; }
}
public static List<Meter> GetMeterUIDList()
{
return meters.Values.ToList();
}
public static List<GSMData> GetGsmdataList()
{
return meters.Values.SelectMany(m => m.Gsmdata)
.OrderBy(t => t.TimeStamp)
.ToList();
}
I need to get all NR for each CellId and a count on how many NR there are on each CellID.
How can i do that?
Perhaps:
var idGroups = meters
.SelectMany(m => m.data)
.GroupBy(d => d.CellID)
.Select(g => new { CellID = g.Key, UniqueNr = g.Select(m => m.NR).Distinct() });
foreach (var g in idGroups)
Console.WriteLine("CellID: {0} Count: {1}", g.CellID, g.UniqueNr.Count());
If the NR's don't need to be unique remove the Distinct.

Categories

Resources