I'm having issues with a program I'm developing. The basic essence of the program is to look through a file of election data and organize it via nested objects. For example, each individual Political Race is an object, and each Political Race object has a list of Candidate and County Results objects and so on.
My current issue revolves around the previously mentioned County Results object. I'm supposed to iterate through the file, and record the Candidate's name and the number of votes they got for each county. Currently I am using nested Ordered Dictionaries to achieve this, but it seems clunky and I am having an issue accessing them. Here's my code so far (listOrdicRows is the text file of the election read into an ordered list):
public CountyResults(List<OrderedDictionary> listOrdicRows, String raceCode)
{
foreach (OrderedDictionary row in listOrdicRows)
{
bool duplicate = false;
foreach (County indivCounty in CountyList)
{
if (indivCounty.countyName == row["county_name"].ToString() && raceCode == row["race_code"].ToString())
{
duplicate = true;
break;
}
}
if (!duplicate && raceCode == row["race_code"].ToString())
{
CountyList.Add(new County(row["county_code"].ToString(), row["county_name"].ToString(), row["precincts"].ToString(), row["precincts_reporting"].ToString()));
}
}
populateCountyDict(listOrdicRows);
}
public void populateCountyDict(List<OrderedDictionary> listOrdicRows) //Dynamically populates County Dictionary
{
foreach (County x in CountyList)
{
String CountyName = x.countyName;
List<OrderedDictionary> candidatesWithVotes = null;
foreach (OrderedDictionary row in listOrdicRows)
{
if (CountyName == row["county_name"].ToString())
{
OrderedDictionary tempDictionary = new OrderedDictionary();
tempDictionary.Add(row["candidate_name"], row["total_votes"]);
candidatesWithVotes.Add(tempDictionary);
}
}
countyDict.Add(CountyName, candidatesWithVotes);
}
}
Any help would be appreciated, as I'm exceedingly stuck. Someone asked for what the file looks like, and here's a few lines
ElectionDate | PartyCode | PartyName | RaceCode | OfficeDesc | CountyCode | CountyName | Juris1num | Juris2num | Precincts | PrecinctsReporting | CanNameLast | CanNameFirst | CanNameMiddle | CanVotes
------------ | --------- | ---------- | -------- | ---------------------------- | ---------- | ---------- | --------- | --------- | --------- | ------------------ | ----------- | ------------ | ------------- | --------
2020/08/18 | REP | Republican | USR | United States Representative | ESC | Escambia | 001 | | 0 | 0 | Gaetz | Matt | | 29272
2020/08/18 | REP | Republican | USR | United States Representative | HOL | Holmes | 001 | | 6 | 6 | Gaetz | Matt | | 2131
2020/08/18 | REP | Republican | USR | United States Representative | OKA | Okaloosa | 001 | | 52 | 52 | Gaetz | Matt | | 25861
Linq can make it a bit easy and readable.
I have created a sample file to just few columns
Next is code
public class ElectionInfo
{
public string Race { get; set; }
public string County { get; set; }
public string FName { get; set; }
public int VoteCnt { get; set; }
}
static void Main(string[] args)
{
Dictionary<string, List<ElectionInfo>> dict1 = File.ReadAllLines(#"C:\x1\TextFile2.txt")
.Select(record => record.Split(','))
.Select(cell => new ElectionInfo() { Race = cell[0], County = cell[1], FName = cell[2], VoteCnt = int.Parse(cell[3]) })
.GroupBy(x => x.Race)
.ToDictionary(t => t.Key, t => t.ToList<ElectionInfo>())
;
Related
I am having trouble selecting the first item in a list that is unique based on two fields, JOB_ID and EMPLOYEE_ID.
Each job should only be assigned to one employee (the one with the lowest OVERALL_SCORE), then move on and assign the next employee.
The List Objects are as follows:
JobMatch.cs
public int JOB_ID { get; set; }
public int JOB_MATCHES_COUNT { get; set; }
EmployeeMatch.cs
public int EMPLOYEE_ID { get; set; }
public int EMPLOYEE_MATCHES_COUNT { get; set; }
Rankings.cs
public int JOB_ID { get; set; }
public int EMPLOYEE_ID { get; set; }
public int TRAVEL_TIME_MINUTES { get; set; }
public int PRIORITY { get; set; }
public int OVERALL_SCORE { get; set; }
Rankings.cs gets an overall score based on the travel time field and
number of matches an Employee/Job has.
EmployeeMatch.cs
+-------------+-------------------+
| EMPLOYEE_ID | EMP_MATCHES_COUNT |
+-------------+-------------------+
| 3 | 1 |
| 4 | 1 |
| 2 | 3 |
| 1 | 4 |
+-------------+-------------------+
JobMatch.cs
+--------+-------------------+
| JOB_ID | JOB_MATCHES_COUNT |
+--------+-------------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 4 |
+--------+-------------------+
Ranking.cs (shortened as to not fill the screen)
+--------+-------------+---------------+
| JOB_ID | EMPLOYEE_ID | OVERALL_SCORE |
+--------+-------------+---------------+
| 4 | 3 | 800 |
| 4 | 4 | 800 |
| 3 | 1 | 800 |
| 3 | 2 | 1200 |
| 2 | 1 | 1600 |
| 2 | 2 | 1800 |
| 4 | 1 | 2000 |
| 4 | 2 | 2100 |
| 1 | 1 | 6400 |
+--------+-------------+---------------+
Basically, the idea is to select the first unique Employee and Job in this list and then the best matches will be put into a separate list, something like the following for the above scenario:
+--------+-------------+---------------+
| JOB_ID | EMPLOYEE_ID | OVERALL_SCORE |
+--------+-------------+---------------+
| 4 | 3 | 800 |
| 3 | 1 | 800 |
| 2 | 2 | 1800 |
+--------+-------------+---------------+
I tried the following but it didn't work as intended:
var FirstOrder = (rankings.GroupBy(u => u.JOB_ID)
.Select(g => g.First())).ToList();
var SecondOrder = (FirstOrder.GroupBy(u => u.EMPLOYEE_ID)
.Select(g => g.First())).ToList();
The idea is choosing first element and then removing corresponding elements from list to make sure next choice is unique, as below:
var rankings = new List<Rankings> {
new Rankings{ JOB_ID= 4,EMPLOYEE_ID= 3, OVERALL_SCORE= 800 },
new Rankings{ JOB_ID= 4,EMPLOYEE_ID= 4, OVERALL_SCORE= 800 },
new Rankings{ JOB_ID= 3,EMPLOYEE_ID= 1, OVERALL_SCORE= 800 },
new Rankings{ JOB_ID= 3,EMPLOYEE_ID= 2, OVERALL_SCORE= 1200 },
new Rankings{ JOB_ID= 2,EMPLOYEE_ID= 1, OVERALL_SCORE= 1600 },
new Rankings{ JOB_ID= 2,EMPLOYEE_ID= 2, OVERALL_SCORE= 1800 },
new Rankings{ JOB_ID= 4,EMPLOYEE_ID= 1, OVERALL_SCORE= 2000 },
new Rankings{ JOB_ID= 4,EMPLOYEE_ID= 2, OVERALL_SCORE= 2100 },
new Rankings{ JOB_ID= 1,EMPLOYEE_ID= 1, OVERALL_SCORE= 6400 },
};
var cpy = new List<Rankings>(rankings);
var result = new List<Rankings>();
while (cpy.Count() > 0)
{
var first = cpy.First();
result.Add(first);
cpy.RemoveAll(r => r.EMPLOYEE_ID == first.EMPLOYEE_ID || r.JOB_ID == first.JOB_ID);
}
result:
+--------+-------------+---------------+
| JOB_ID | EMPLOYEE_ID | OVERALL_SCORE |
+--------+-------------+---------------+
| 4 | 3 | 800 |
| 3 | 1 | 800 |
| 2 | 2 | 1800 |
+--------+-------------+---------------+
Really, if you're trying to get the best score for the job, you don't need to select by unique JOB_ID/EMPLOYEE_ID, you need to sort by JOB_ID/OVERALL_SCORE, and pick out the first matching employee per JOB_ID (that's not already in the "assigned list").
You could get the items in order using LINQ:
var sorted = new List<Ranking>
(
rankings
.OrderBy( r => r.JOB_ID )
.ThenBy( r => r.OVERALL_SCORE )
);
...and then peel off the employees you want...
var best = new List<Ranking>( );
sorted.ForEach( r1 =>
{
if ( !best.Any
(
r2 =>
r1.JOB_ID == r2.JOB_ID
||
r1.EMPLOYEE_ID == r2.EMPLOYEE_ID
) )
{
best.Add( r1 );
}
} );
Instead of using Linq to produce a sorted list, you could implement IComparable<Ranking> on Ranking and then just sort your rankings:
public class Ranking : IComparable<Ranking>
{
int IComparable<Ranking>.CompareTo( Ranking other )
{
var jobFirst = this.JOB_ID.CompareTo( other.JOB_ID );
return
jobFirst == 0?
this.OVERALL_SCORE.CompareTo( other.OVERALL_SCORE ):
jobFirst;
}
//--> other stuff...
}
Then, when you Sort() the Rankings, they'll be in JOB_ID/OVERALL_SCORE order. Implementing IComparable<Ranking> is probably faster and uses less memory.
Note that you have issues...maybe an unstated objective. Is it more important to fill the most jobs...or is more important to find work for the most employees? The route I took does what you suggest, and just take the best employee for the job as you go...but, maybe, the only employee for job 2 may be the same as the best employee for job 1...and if you put him/her on job 1, you might not have anybody left for job 2. It could get complicated :-)
Basically you could use System.Linq.Distinct method reinforced with the custom equality comparer IEqualityComparer<Ranking>. The System.Linq provide this method out of the box.
public class Comparer : IEqualityComparer<Ranking>
{
public bool Equals(Ranking l, Ranking r)
{
return l.JOB_ID == r.JOB_ID || l.EMPLOYEE_ID == r.EMPLOYEE_ID;
}
public int GetHashCode(Ranking obj)
{
return 1;
}
}
The trick here is with the GetHashCode method, and then as simple as this
rankings.Distinct(new Comparer())
I have a Branch List, each one has a Number N of employees, I have a Branch object and a NumberEmployees property, now I need to iterate over that list sending the number of employees per block, I explain better with the following table: I order the List by Number of Employees, so far no problem.
+---------+-----------+
| Branch | Employees |
+---------+-----------+
|MEXICO | 800 |
|USA | 700 |
|INDIA | 500 |
|CHINA | 400 |
|AUSTRALIA| 300 |
+---------+-----------+
Now iterate through a list but dividing the number of employees into blocks something like this:
+-----------+------------+-------------+------------+
| Branch | FirstGroup | SecondGroup | ThirdGroup |
+-----------+------------+-------------+------------+
| Mexico | 267 | 267 | 267 |
| USA | 234 | 234 | 234 |
| India | 167 | 167 | 167 |
| China | 134 | 134 | 134 |
| Australia | 100 | 100 | 100 |
+-----------+------------+-------------+------------+
In the end I think the list that should result would be:
+-----------+-----------+
| Branch | Employees |
+-----------+-----------+
| Mexico | 267 |
| USA | 234 |
| India | 167 |
| China | 134 |
| Australia | 100 |
| Mexico | 267 |
| USA | 234 |
| India | 167 |
| China | 134 |
| Australia | 100 |
| Mexico | 267 |
| USA | 234 |
| India | 167 |
| China | 134 |
| Australia | 100 |
+-----------+-----------+
So far I can only order the List.
double TotalEmployees = ListBranch.Sum(item => item.EmployeeNumber);
double blockSize = TotalEmployees / ListBranch.Count();
double sizeQuery = Math.Ceiling(blockSize);
foreach (Branch branch in ListBranch.OrderByDescending(f => f. EmployeeNumber))
{
//to do
}
I appreciate your valuable help for any clues you can give me
This might do the trick for you
List<BranchEmployee> be = new List<BranchEmployee>();
be.Add(new BranchEmployee() { Branch = "MEXICO", Employee = 800 });
be.Add(new BranchEmployee() { Branch = "USA", Employee = 700 });
be.Add(new BranchEmployee() { Branch = "INDIA", Employee = 500 });
be.Add(new BranchEmployee() { Branch = "CHINA", Employee = 400 });
be.Add(new BranchEmployee() { Branch = "AUSTRALIA", Employee = 300 });
List<BranchEmployee> ExpectedBE = new List<BranchEmployee>();
for(int i = 0; i <= 2; i++)
{
foreach(BranchEmployee smbe in be)
{
ExpectedBE.Add(new BranchEmployee()
{
Branch = smbe.Branch,
Employee = smbe.Employee / 3
});
}
}
What I see is that every group has equal number of employees that is the total number of employees divided by 3.
To look the data in the way you have shown I have created a class like this
public class BranchEmployee
{
public string Branch { get; set; }
public int Employee { get; set; }
}
Animal:
+----------+---------+--------+
| animalId | animal | typeId |
+----------+---------+--------+
| 1 | snake | 1 |
| 2 | cat | 2 |
+----------+---------+--------+
AnimalType:
+--------+----------+
| typeId | type |
+--------+----------+
| 1 | reptile |
| 2 | mammal |
+--------+----------+
AnimalBody:
+--------+-------+----------+
| bodyId | body | animalId |
+--------+-------+----------+
| 1 | tail | 1 |
| 2 | eye | 1 |
| 3 | tail | 2 |
| 4 | eye | 2 |
| 5 | leg | 2 |
+--------+-------+----------+
Table relation:
Animal.typeId = AnimalType.typeId
Animal.animalId = AnimalBody.animalId
I need to output them into JSON format as below:
{
animalId: 1,
animal: "snake",
type: "reptile",
body: {
"tail", "eye"
}
},
{
animalId: 2,
animal: "cat",
type: "mammal",
body: {
"tail", "eye", "leg"
}
}
How can I achieve this with pure LINQ clauses instead of method?
I have tried:
from animal in db.Animal
join animalType in db.AnimalType on animal.typeId equals animalType.typeId
select new
{
animalId = animal.animalId,
animal = animal.animal,
type = animalType.type,
body = ?
};
Assuming you want the body element to be an array of body parts, here's what you should do:
Join Animals with AnimalTypes:
var animalsWithType = db.Animals.Join(
animal => animal.typeId,
animalType => animalType.typeId,
(animal, type) => new { animal, type });
Afterwards, GroupJoin animalsWithType with AnimalBody elements:
var result = animalsWithType.GroupJoin(db.AnimalBodies,
animalWithType => animalWithType.animal.animalId,
body => body.animalId,
(animalWithType, bodyParts) => new
{
animalId = animalWithType.animal.animalId,
animal = animalWithType.animal.animal,
type = animalWithType.type.type,
body = bodyParts.Select(part => part.body)
});
Now, just export the result to JSON and you should be set.
I have a collection like this:
Order //Collection
|-OrderId
|-DateOfOrder
|-PartyName
|-OrderDetails //Collection
| |-ItemName
| |-Quantity
| |-Rate
| |-Amount
|-Dispatch //Collection
| |-InvoiceNo
| |-DateOfDispatch
| |-DispatchDetails //Collection
| | |-ItemName
| | |-Quantity
| | |-Rate
| | |-Amount
Now I want to flatten this collection, so that I can show data in below mentioned pattern:
OrderId | DateOfOrder | PartyName | InvoiceNo | DateOfDispatch | Dispatch ItemName | Dispatch Quantity | Dispatch Rate | Dispatch Amount
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
I have tried:
Orders = new ObservableCollection<Order>(orderService.GetAllOrders()
.SelectMany(x => x.Dispatches)
.SelectMany(x => x.DispatchDetails)
.ToList()
);
The relation between OrderDetails and DispatchDetails is not clear to me, and DispatchItemTransactions seems to be missing from your data structure. Anyway, I hope you find this simple approach useful:
foreach(var order in Orders)
foreach(var dispatch in order.Dispatches)
foreach(var dispatchDetail in dispatch.DispatchDetails)
{
// now construct your record object from order.OrderId, order.DateOfOrder, ... , dispatchDetail.Amount
}
For this to work you'll need to construct new Order and Dispatch objects. Also query syntax will make this much easier to read.
Orders = new ObservableCollection<Order>(
from o in orderService.GetAllOrders
from d in o.Dispatches
from dd in d.DispathDetails
select new Order
{
OrderId = o.OrderId,
DateOfOrder = o.DateOfOrder,
PartyName = o.PartyName,
Dispatches = new List<Dispatch>
{
new Dispatch
{
InvoiceNo = d.InvoiceNo
DateOfDispatch = d.DateOfDispatch
DispatchDetails = new List<DispatchDetail> { dd }
}
}
});
Though instead of a collection of Order you might want to just use an anonymous class instead
from o in orderService.GetAllOrders
from d in o.Dispatches
from dd in d.DispathDetails
select new
{
OrderId = o.OrderId,
DateOfOrder = o.DateOfOrder,
PartyName = o.PartyName,
InvoiceNo = d.InvoiceNo
DateOfDispatch = d.DateOfDispatch,
DispatchItemName = dd.ItemName,
DispatchQuantity = dd.Quantity,
DispatchRate = dd.Rate,
DispatchAmount = dd.Amount
}
So I'm attempting to populate a table with seed data in EF5. I have an Enum of all 50 states and DC. I also have a lookup table of RequestTypes with IDs 1-6. It would be something like this:
+----+----------+-------------+------------+
| Id | State | SurveyId | RequestType|
+----+----------+-------------+------------+
| 1 | Alabama | 0 | 1 |
| 2 | Alabama | 0 | 2 |
| 3 | Alabama | 0 | 3 |
| 4 | Alabama | 0 | 4 |
| 5 | Alabama | 0 | 5 |
| 6 | Alabama | 0 | 6 |
+----+----------+-------------+------------+
The model that represents this table:
public class StateSurveyAssignment{
public long Id { get; set; }
public string State { get; set; }
public long RequestTypeId { get; set; }
public long SurveyId { get; set; }
}
And the code to seed the database in the Configuration.cs:
foreach (var state in Enum.GetValues(typeof(State))) {
foreach (var type in context.RequestTypes){
context.StateSurveyAssignments.AddOrUpdate(
ssa => ssa.Id,
new StateSurveyAssignment{
State = state.ToString(),
RequestTypeId = type.Id
}
);
}
}
My problem is that instead of updating/doing nothing to unchanged records, the seed method is duplicating each row. I've attempted to manually set the Id but had no luck.
EDIT:
This is what the database duplication looks like:
+----+----------+-------------+------------+
| Id | State | SurveyId | RequestType|
+----+----------+-------------+------------+
| 1 | Alabama | 0 | 1 |
| 2 | Alabama | 0 | 2 |
| 3 | Alabama | 0 | 3 |
| 4 | Alabama | 0 | 4 |
| 5 | Alabama | 0 | 5 |
| 6 | Alabama | 0 | 6 |
| ...| ... | ... | ... |
|307 | Alabama | 0 | 1 |
|308 | Alabama | 0 | 2 |
|309 | Alabama | 0 | 3 |
|310 | Alabama | 0 | 4 |
|311 | Alabama | 0 | 5 |
|312 | Alabama | 0 | 6 |
+----+----------+-------------+------------+
My Solution
I swear I'd tried setting my own Id at some point but tried it again per the answer and it seems to have worked. My final solution:
int counter = 1;
foreach (var state in Enum.GetValues(typeof(State))) {
foreach (var type in context.RequestTypes){
context.StateSurveyAssignments.AddOrUpdate(
ssa => ssa.Id,
new StateSurveyAssignment{
Id = counter,
State = state.ToString(),
RequestTypeId = type.Id
}
);
counter++;
}
}
The problem could be that the Id property in your StateSurveyAssignment class is an Identity column in the database.
This means that each row is not unique.
For example you try to insert the following several times using AddOrUpdate()
var model = new StateSurveyAssignment
{
State = "Alabama",
RequestTypeId = 1L,
SurveyId = 0L
};
Then each entry would have a different Id and thus you'll have duplicates.