LINQ - can't figure out sorting grouped data - linq

I have an array of Person pocos, populated below. I'm trying display them alphabetically by Province, then by LastName within the Province. I'm using grouping and I can get the Provinces sorted fine, just not sure how to order the people within the province group.
This code:
Person[] people = new Person[]
{
new Person() { FirstName = "Tony", LastName = "Montana", Age = 39, HomeProvince = "Ontario" },
new Person() { FirstName = "Bill", LastName = "Smith", Age = 23, HomeProvince = "Ontario" },
new Person() { FirstName = "Jane", LastName = "Doe", Age = 23, HomeProvince = "Alberta" },
new Person() { FirstName = "John", LastName = "Doe", Age = 23, HomeProvince = "Alberta" },
new Person() { FirstName = "Alex", LastName = "DeLarge", Age = 19, HomeProvince = "British Columbia" },
new Person() { FirstName = "Travis", LastName = "Bickle", Age = 42, HomeProvince = "Quebec" },
new Person() { FirstName = "Ferris", LastName = "Beuller", Age = 17, HomeProvince = "Manitoba" },
new Person() { FirstName = "Maggie", LastName = "May", Age = 23, HomeProvince = "Ontario" },
new Person() { FirstName = "Mickey", LastName = "Mouse", Age = 93, HomeProvince = "Alberta" },
new Person() { FirstName = "Frank", LastName = "Darabont", Age = 49, HomeProvince = "Ontario" }
};
var query =
from person in people
group person by person.HomeProvince into g
orderby g.Key
select new { Province = g.Key, People = g };
foreach (var prov in query)
{
Console.WriteLine("{0}: ", prov.Province);
foreach (var person in prov.People)
{
Console.WriteLine(" {0} {1}, {2}", person.FirstName, person.LastName, person.Age);
}
}
Gives me this output:
Alberta:
Jane Doe, 23
John Doe, 23
Mickey Mouse, 93
British Columbia:
Alex DeLarge, 19
Manitoba:
Ferris Beuller, 17
Ontario:
Tony Montana, 39
Bill Smith, 23
Maggie May, 23
Frank Darabont, 49
Quebec:
Travis Bickle, 42
As you can see, the Provinces are listed alphabetically but how do I list the people within the province (i.e for Ontario I want this order: Darabont, Montana, May, Smith).

Assuming that you want alphabetical order by LastName then change this:
select new { Province = g.Key, People = g };
to:
select new { Province = g.Key, People = g.OrderBy(p => p.LastName) };
But note that your example "Darabont, Montana, May, Smith" is not quite in alphabetical order. I assume that this was just a mistake on your part, but if this is actually the order you want, please explain the rule you are using to generate this ordering.

should be able to, after the select statement, to orderby(person => person.LastName);

Related

Updating Collection from other collection for matching items

I have two collections as mentioned below. I have update two properties of "trade" from the other collection "refData" if those values exists in "refData".
Model:
class Trade
{
public int Id { get; set; }
public string PayIndex { get; set; }
public string RecIndex { get; set; }
public string PayCurrency { get; set; }
public string RecCurrency { get; set; }
}
class RefData
{
public string IndexLabel { get; set; }
public string Symbol { get; set; }
}
Sample Date:
var refData = new List<RefData>
{
new RefData { IndexLabel = "A1", Symbol="ABC1"},
new RefData { IndexLabel = "A2", Symbol="ABC2"},
new RefData { IndexLabel = "B1", Symbol="BCD1"},
new RefData { IndexLabel = "B2", Symbol="BCD2"},
};
var trades = new List<Trade>
{
new Trade { Id = 1, PayIndex = "A1", RecIndex = "B1"},
new Trade { Id = 2, PayIndex = "A2", RecIndex = ""},
new Trade { Id = 3, PayIndex = "", RecIndex = "B2"},
new Trade { Id = 4, PayIndex = "A3", RecIndex = "B3"}
};
I want to update PayCurrency and RecCurrency of "trades" with Symbol property of "refData" if trade's PayIndex and RecCurrency exists in "refData".
Output:
var Output = new List<Trade>
{
new Trade { Id = 1, PayIndex = "A1", RecIndex = "B1", PayCurrency = "ABC1", RecCurrency="BCD1"},
new Trade { Id = 2, PayIndex = "A2", RecIndex = "", PayCurrency = "ABC2", RecCurrency=""},
new Trade { Id = 3, PayIndex = "", RecIndex = "B2", PayCurrency = "", RecCurrency="BCD2"},
new Trade { Id = 4, PayIndex = "A3", RecIndex = "B3", PayCurrency = "", RecCurrency=""}
};
For c#6 and above you can do like below
var result = trades.Select(t => new Trade() {
Id= t.Id,
PayIndex = t.PayIndex,
RecIndex = t.RecIndex,
PayCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.PayIndex.ToLower()))?.Symbol ?? "",
RecCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.RecIndex.ToLower()))?.Symbol ?? ""
}).ToList();
For Older versions
var result = trades.Select(t => new Trade() {
Id= t.Id,
PayIndex = t.PayIndex,
RecIndex = t.RecIndex,
PayCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.PayIndex.ToLower())) != null ? refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.PayIndex.ToLower())).Symbol : "",
RecCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.RecIndex.ToLower())) != null ? refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.RecIndex.ToLower())).Symbol : ""
}).ToList();
Here is working example
Update using #SAJ answer
var output = (from r in trades
join p in refData on r.PayIndex equals p.IndexLabel
into g1
from s in g1.DefaultIfEmpty()
join t in refData on r.RecIndex equals t.IndexLabel into g2
from a in g2.DefaultIfEmpty()
select Trade { Id=r.Id,PayIndex=r.PayIndex,RecIndex=r.RecIndex, RecCurrency = a != null ? a.Symbol : "", PayCurrency = s != null ? s.Symbol : ""}).ToList();
You can try this
var output = (from r in trades
join p in refData on r.PayIndex equals p.IndexLabel
into g1
from s in g1.DefaultIfEmpty()
join t in refData on r.RecIndex equals t.IndexLabel into g2
from a in g2.DefaultIfEmpty()
select new { r, RecSymbol = a?.Symbol, PaySymbol = s?.Symbol }).ToList();
output.ForEach(o =>
{
o.r.PayCurrency = o.PaySymbol;
o.r.RecCurrency = o.RecSymbol;
});

Adding a column to an existing table in Lua

In Lua, how do I insert a new column on a table like the one below?
table t = {
{name = "John", age = 19, sex = "M"},
{name = "Susan", age = 20, sex = "F"},
{name = "Paul", age = 18, sex = "M"}
}
I want to put a column id before the name, so the table could be like this:
table t = {
{id = 1, name = "John", age = 19, sex = "M"},
{id = 2, name = "Susan", age = 20, sex = "F"},
{id = 3, name = "Paul", age = 18, sex = "M"}
}
PS: the data of this table is coming from a file like the one below:
entry {name = "John", age = 19, sex = "M"}
entry {name = "Susan", age = 20, sex = "F"}
entry {name = "Paul", age = 18, sex = "M"}
and I'm using this code to insert this data into the table:
data = {}
text = file:read()
do
function entry(entrydata)
table.insert(data, entrydata)
end
thunk = load(text, nil, nil, {entry = entry})
thunk()
end
for i,v in ipairs(t) do
v.id=i
end
Alternately, you could set the value during loading:
data = {}
text = file:read()
do
local index=1
function entry(entrydata)
entrydata.id=index
index=index+1
table.insert(data, entrydata)
end
thunk = load(text, nil, nil, {entry = entry})
thunk()
end

Linq query: Group by Multiple Columns

I have a list that looks like this.
-100 Smith, Jane $1000
-100 Smith, John $1100.00
-100 Smith, Cole $840.00
-110 Jones, Harry $1270.00
-110 Jones, Diane $870.00
-111 Jones, Richard $1560.00
Using LINQ, I wish to write a query that will allow me to SUM up the values by family.
The first identifier is the family id.
For the above set of records, my output will look like:
-100 Smith $2940.00
-110 Jones $2140.00
-111 Jones $1560.00
Here's my code:
static void Main(string[] args)
{
_fi = FillIncome();
var query = (from f in _fi group f by f.familyId into delta select new {familyId = delta.Key, amount = delta.Sum(x => x.income) });
foreach (var q in query)
{
Console.WriteLine(q);
}}
static List<FamilyIncome> FillIncome()
{
var income = new List<FamilyIncome>();
var fi = new FamilyIncome {familyId = -100, lastname = "Smith", firstname = "Jane", income = 1000};
income.Add(fi);
fi = new FamilyIncome { familyId = -100, lastname = "Smith", firstname = "John", income = 1100 };
income.Add(fi);
fi = new FamilyIncome { familyId = -100, lastname = "Smith", firstname = "Cole", income = 840 };
income.Add(fi);
fi = new FamilyIncome { familyId = -110, lastname = "Jones", firstname = "Harry", income = 1270 };
income.Add(fi);
fi = new FamilyIncome { familyId = -110, lastname = "Jones", firstname = "Diane", income = 970 };
income.Add(fi);
fi = new FamilyIncome { familyId = -111, lastname = "Jones", firstname = "Richard", income = 1600 };
income.Add(fi);
return income;
}
Let's assume the class representing your data item looks like this:
class DataItem
{
public int FamilyId { get; set; }
public string FamilyName { get; set; }
public string FirstName { get; set; }
public decimal Salary { get; set; }
}
Then your data should be presented as
private static DataItem[] items = new[]
{
new DataItem { FamilyId = -100, FamilyName = "Smith", FirstName = "Jane", Salary = 1000},
new DataItem { FamilyId = -100, FamilyName = "Smith", FirstName = "John", Salary = 1100},
new DataItem { FamilyId = -100, FamilyName = "Smith", FirstName = "Cole", Salary = 840},
new DataItem { FamilyId = -110, FamilyName = "Jones", FirstName = "Harry", Salary = 1270},
new DataItem { FamilyId = -110, FamilyName = "Jones", FirstName = "Diane", Salary = 870},
new DataItem {FamilyId = -111, FamilyName = "Jones", FirstName = "Richard", Salary = 1560},
};
The query producing the desired output will be the following:
var groupedItems =
from item in items
group item by new {item.FamilyId, item.FamilyName}
into family
select new {family.Key.FamilyId, family.Key.FamilyName, Sum = family.Sum(item => item.Salary)};
And to output these grouped items you can use something like
foreach (var groupedItem in groupedItems)
{
Console.WriteLine(
"{0}\t{1}\t{2}",
groupedItem.FamilyId,
groupedItem.FamilyName,
groupedItem.Sum);
}
Hope this helps

Combine properties values from a custom List with LINQ

Lets assume I have a list of Persons, in the List I have the following objects:
Person = { ID= 1, State="CA"}
Person = { ID= 2, State="PA"}
Person = { ID= 1, State="NY"}
Person = { ID= 1, State="OH"}
Person = { ID= 3, State="FL"}
Person = { ID= 2, State="KC"}
How do I get a new List Where I can have new Persons by ID only once and if repeated get the State value and put it in the new Person object separated by comma. For example the new List will be
Person = { ID= 1, State="CA,NY,OH"}
Person = { ID= 2, State="PA,KC"}
Person = { ID= 3, State="FL"}
Is there a way to achieve this?
Use Enumerable.GroupBy and String.Join:
var result = persons.GroupBy(p => p.ID)
.Select(g => new Person{
ID = g.Key,
State = string.Join(",", g.Select(p => p.State))
}).ToList();
here is the extension method version
var persons = Person.GroupBy(p => p.ID).Select(p => new Person() { ID = p.Key, State = String.Join(",", p.Select(p2 => p2.State).ToArray()) }).ToList();

one to many relationship in entity framewrok 4.1 code first

I am initializing the entities like this:
TasksListDB db = new TasksListDB();
public ActionResult Index()
{
var tasks1 = new List<Task>()
{
new Task { Id=1, Name = "Task 1", Difficulty = 1, DateCreated = DateTime.Parse("1/12/2011") , IsDone= true },
new Task { Id=2, Name = "Task 2", Difficulty = 2, DateCreated = DateTime.Parse("11/2/2011") , IsDone = false}
};
var tasks2 = new List<Task>()
{
new Task { Id=3, Name = "Task 3", Difficulty = 3, DateCreated = DateTime.Parse("11/2/2011") , IsDone = false},
new Task { Id=4, Name = "Task 4", Difficulty = 5, DateCreated = DateTime.Parse("1/2/2010") , IsDone= true }
};
tasks1.ForEach(t => db.Tasks.Add(t));
tasks2.ForEach(t => db.Tasks.Add(t));
var Persons = new List<Person> {
new Person { Id= 1 , Age= 10, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" },
new Person { Id= 2 , Age= 10, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" },
new Person { Id= 3 , Age= 10, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" },
new Person { Id= 4 , Age= 10, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" }};
Persons.ForEach(p => db.Persons.Add(p));
return View(db.Tasks);
}
my db context looks like this:
public class TasksListDB : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Task> Tasks { get; set; }
}
I want to assign tasks to persons how can I do this ?
My model looks like this :
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string EmailAddress { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public DateTime DateCreated { get; set; }
[Required]
[Range(1,5,ErrorMessage="Difficulty must be between 1 and 5")]
public int Difficulty { get; set; }
public bool IsDone { get; set; }
public virtual Person Person { get; set; }
}
When I run my mvc application, Person and Task tables are created but juntion table PersonTask not created.
[EDIT]
I am assigning tasks like this in initializer class:
var t1 = new Task { Id = 1, Name = "Urgent Task", DateCreated = DateTime.Now, Difficulty = 2, IsDone = true };
var t2 = new Task { Id = 2, Name = "Business Task", DateCreated = DateTime.Now, Difficulty = 1, IsDone = true };
var t3 = new Task { Id = 3, Name = "Home Task", DateCreated = DateTime.Now, Difficulty = 2, IsDone = false };
context.Tasks.Add(t1);
context.Tasks.Add(t2);
context.Tasks.Add(t3);
var Persons = new List<Person> {
new Person { Id= 1 , Age= 40, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed", Tasks= new List<Task> { t1,t2 }},
new Person { Id= 2 , Age= 30, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" , Tasks= new List<Task> { t1} },
new Person { Id= 3 , Age= 29, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" , Tasks= new List<Task> { t3,t2 } },
new Person { Id= 4 , Age= 35, EmailAddress= "asif_hameed_37#hotmail.com", FirstName= "Asif", LastName="Hameed" , Tasks= new List<Task> { t1,t3 } }};
context.Persons.Add(Persons[0]);
context.Persons.Add(Persons[1]);
context.Persons.Add(Persons[2]);
context.Persons.Add(Persons[3]);
context.SaveChanges();
but when i see the task table in sql server, it looks like this:
Id Name DateCreated Difficulty IsDone Person_Id
1 Urgent Task 2011-04-24 19:32:03.990 2 1 4
2 Business Task 2011-04-24 19:32:03.990 1 1 3
3 Home Task 2011-04-24 19:32:03.990 2 0 4
I assume that person table should have tasks not the task table should have person Id
Please suggest solution.
Junction table will not be created because you have defined one-to-many relation not many-to-many. The Task entity in your model can be assigned only to single Person not to many persons.
If you want to assing Task to Person simply run:
person.Tasks.Add(task);

Resources