I have a list of Person and a list of BirthDates and I would like to intersect person.BirthYear with BirthDates.Year
Intersects seems to need both lists to be of same type so my question is how to have a func or so which will allow to me write my own custom matching logic?
You can perform a Join which doesn't needs both sequences to be of same type.
This answer should help you with the syntax.
Here is code snippet for your case:
using System;
using System.Linq;
namespace Intersects
{
class Person
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
class Program
{
static void Main(string[] args)
{
var persons = new[]
{
new Person() {Name = "Jack", BirthDate = new DateTime(1990, 1, 1)},
new Person() {Name = "Joe", BirthDate = new DateTime(1970, 9, 9)},
new Person() {Name = "Ivan", BirthDate = new DateTime(1991, 2, 2)},
};
var birthDates = new[]
{
new DateTime(1990, 1, 1),
new DateTime(1991, 2, 2),
new DateTime(1991, 3, 3),
};
var joined = from p in persons
join bd in birthDates
on p.BirthDate.Year equals bd.Year // Your own custom logic
select p;
foreach (var person in joined)
{
Console.WriteLine(person.Name);
}
// Output:
//Jack
//Ivan
//Ivan
}
}
}
Related
I have a class like as follows:
public class ActualClass
{
public string BookName { get; set; }
public string IssuerName { get; set; }
public DateTime DateOfIssue { get; set; }
public bool Status { get; set; }
}
It has following data in the table:
I would like to group them by IssuerName and DateOfIssue for the following viewModel class:
public class ViewModel
{
public string IssuerName { get; set; }
public DateTime DateOfIssue { get; set; }
public List<string> Books { get; set; }
}
And data will be displayed as follows: (Screenshot data will be replaced by the previous table data after successful grouping)
Special attention: Is there anything wrong in my ViewModel according to my expectation?
I tried a lot after following some stackoverflow answers but none did work for me. Any help will be highly appreciated.
The code I have tried:
var viewmodel = from b in db.BookIssues
group b by new
{
b.IssuerName,
b.DateOfIssue
}
into g
select new ViewModel()
{
Name = g.key.IssuerName,
DateOfIssue = g.Key.DateOfIssue,
Books = g.ToList() //Actually this line of code is not working
};
Books = g.ToList() //Actually this line of is not working
Probably because Books property is type of List<string>, not List<ActualClass>.
Can you please try this query, I added b.Select(bn => bn.BookName).ToList() to extract only names of books:
var books = new List<ActualClass>
{
new ActualClass { BookName = "A", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "1" },
new ActualClass { BookName = "B", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "1" },
new ActualClass { BookName = "C", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "1" },
new ActualClass { BookName = "D", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "2" },
new ActualClass { BookName = "E", DateOfIssue = new DateTime(2015, 10, 10, 12, 10, 0), IssuerName = "2" },
new ActualClass { BookName = "F", DateOfIssue = new DateTime(2015, 10, 10, 12, 10, 0), IssuerName = "2" }
};
var result = books.GroupBy(x => new { x.IssuerName, x.DateOfIssue })
.Select(b => new ViewModel
{
Books = b.Select(bn => bn.BookName).ToList(),
// Accessing to DateOfIssue and IssuerName from Key.
DateOfIssue = b.Key.DateOfIssue,
IssuerName = b.Key.IssuerName
});
I grouped by: x.IssuerName, x.DateOfIssue. I did that by passing anonymous type in GroupBy() with following manner: x => new { x.IssuerName, x.DateOfIssue }.
Now they are in key and you can access to IssuerName and DateOfIssue from KEY in SELECT statement like in following: b.Key.IssuerName and b.Key.DateOfIssue.
if you need to select list of books from group result, you need Books = v.Select(c=>c.BookName).ToList() also note that in case of you have time in issue date time you may need to group by only the date part using EntityFunctions.TruncateTime function. if you only storing date only then you can ignore this function.
var viewmodel = db.BookIssues.GroupBy(x=>new {IssuerName =x.IssuerName, DateOfIssue=EntityFunctions.TruncateTime(x.DateOfIssue) })
.Select(v=>new ViewModel(){IssuerName =v.Key.IssuerName, DateOfIssue = v.Key.DateOfIssue, Books = v.Select(c=>c.BookName).ToList() })
.ToList();
I was wondering whether you know using LINQ in C# to pull a list of objects from a collection that satisfies a condition?
I am trying to pull a list of Person objects from a list whose IDs match in an integer list. Please see the code below (I am trying to pull all person objects whose IDs are in the integer list).
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
...
var intList = new List<int>() { 1, 2, 3, 4 };
var perList = new List<Person>
{
new Person {Id = 1, FirstName = "Thomas", LastName = "Joseph"},
new Person {Id = 2, FirstName = "Joseph", LastName = "Austin"},
new Person {Id = 3, FirstName = "Lee", LastName = "Hentry"},
new Person {Id = 4, FirstName = "Abraham", LastName = "Tony"}
};
You can use the Where and Contains methods:
var people = perList
.Where(person => intList.Contains(person.Id))
.ToList();
You can use the Where and Any methods:
var filteredPeople = perList.Where(person => intList.Any(person.Id)).ToList();
I have created a query that only shows students that have a date of birth that is less than 1990. I am trying to express this same query as a Lambda query but do not know how to go about it. This is my code so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
public DateTime DateOfBirth { get; set; }
}
class LINQ2
{
static void Main()
{
IEnumerable<Student> students = new List<Student>()
{
new Student {FirstName = "Jim", LastName = "Smith", DateOfBirth = new DateTime(1990, 5, 21), ID = 1},
new Student {FirstName = "Diane", LastName = "Sawyer", DateOfBirth = new DateTime(1992, 11, 1), ID = 2},
new Student {FirstName = "Steve", LastName = "Thomas", DateOfBirth = new DateTime(1994, 4, 4), ID = 3},
new Student {FirstName = "Pablo", LastName = "Dicaz", DateOfBirth = new DateTime(1973, 3, 30), ID = 4},
new Student {FirstName = "Hannu", LastName = "Korppi", DateOfBirth = new DateTime(1988, 6, 16), ID = 5},
new Student {FirstName = "Marie", LastName = "St. Claude", DateOfBirth = new DateTime(1982, 1, 19), ID = 6}
};
IEnumerable<Student> query = from s in students
where s.DateOfBirth.Year < 1990
orderby s.FirstName
select s;
foreach (Student stud in query)
{
Console.WriteLine(stud.FirstName);
Console.ReadLine();
}
}
}
}
If you mean the extension method syntax by Lambda query then you can do it like this:
var query = students
.Where(s => s.DateOfBirth.Year < 1990)
.OrderBy(s => s.FirstName);
suppose that I have this List of Employees representing a table of employees.
public class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public string Function { get; set; }
public decimal Salary { get; set; }
public DateTime EntryDate { get; set; }
public static List<Employee> GetEmployeesList()
{
return new List<Employee>() {
new Employee() { EntryDate = new DateTime(2011, 05, 01), Name = "Fons", Department = "Finance", Function = "Trader", Salary = 6500 },
new Employee() { EntryDate = new DateTime(2013, 05, 02), Name = "Mary", Department = "Finance", Function = "BusinessAnalyst", Salary = 2500 },
new Employee() { EntryDate = new DateTime(2012, 04, 03), Name = "Alex", Department = "Finance", Function = "Trader", Salary = 2100 },
new Employee() { EntryDate = new DateTime(2013, 05, 04), Name = "Jim", Department = "R&D", Function = "Trainer", Salary = 3300 },
new Employee() { EntryDate = new DateTime(2010, 06, 05), Name = "Ellen", Department = "Dev", Function = "Developer", Salary = 2500 },
new Employee() { EntryDate = new DateTime(2000, 09, 06), Name = "Mike", Department = "Dev", Function = "Consultant", Salary = 5100 },
new Employee() { EntryDate = new DateTime(1999, 03, 07), Name = "Jack", Department = "R&D", Function = "Developer", Salary = 6100 },
new Employee() { EntryDate = new DateTime(1989, 01, 08), Name = "Demy", Department = "Dev", Function = "Consultant", Salary = 3300 }};
}
}
I want to be able to select only desired columns to be displayed.
Someting like :
public static List<Employee> SelectColumnsFromTable(List<Employee> employees, int[] selectedColumns)
{
// only select colums 1, 3 and 4
}
I have seen that it is possible with SQL and GridView, but in my case, the result will be printed on the console.
Is it possible using C# and Linq ?
As I understand the question, it is important to select specific properties of a class based on their index. If the relevant indices are provided to you by the user, you can use reflection to access the properties dynamically. The key points are Type.GetProperties and PropertyInfo.GetValue. I've put together a small sample to demonstrate:
using System;
using System.Collections.Generic;
using System.Linq;
public class Employee
{
public int Id {get; set;}
public string FirstName { get; set;}
public string LastName {get; set;}
}
public class Test
{
private static string[] GetColumnValues(Employee emp, params int[] cols)
{
var props = emp.GetType().GetProperties();
var values = new List<string>();
foreach(var i in cols)
{
if (i >= 0 && i < props.Length)
{
object value = props[i].GetValue(emp, null);
values.Add(value == null ? string.Empty : value.ToString());
}
}
return values.ToArray();
}
public static void Main()
{
var emp = new Employee() { Id = 1, FirstName = "John", LastName = "Smith" };
var values = GetColumnValues(emp, 0, 2);
Console.WriteLine(string.Join("\t", values));
}
}
Please note that referencing the properties by their index might not be very deterministic of you change the implementation later on. So selecting by the property's name might be more stable. Also, the column selector function GetColumnValues does not return Employees, but the values as a string array so you can use it in String.Join. You can use the function in Linq:
var rows = from x in listOfEmps select GetColumnValues(x, 0, 2);
foreach(var row in rows)
Console.WriteLine(string.Join("\t", row));
var items = (from i in v.db.DatabaseName
orderby i.EmpID descending
select new {i.Name, i.Function,i.Salary}).ToList();
var list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)//your condition here
.Select(row => new
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList();
Or you can define class:
public class myClass
{
public int demoid;
public string demoname;
}
and then:
List<myClass> list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)
.Select(row => new myClass
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList<myClass>();
this is selecting a particular value to a list. However you can use IList<myClass> classcollection= new List<myClass>(); and then add the particular list to class1 based on condition.
Note: here class collection can hold multiple list as u want the columns 1,3,4
I have the following tables:
Person(Id, FirstName, LastName)
{
(1, "John", "Doe"),
(2, "Peter", "Svendson")
(3, "Ola", "Hansen")
(4, "Mary", "Pettersen")
}
Sports(Id, Name)
{
(1, "Tennis")
(2, "Soccer")
(3, "Hockey")
}
SportsPerPerson(Id, PersonId, SportsId)
{
(1, 1, 1)
(2, 1, 3)
(3, 2, 2)
(4, 2, 3)
(5, 3, 2)
(6, 4, 1)
(7, 4, 2)
(8, 4, 3)
}
Looking at the tables, we can conclude the following facts:
John plays Tennis
John plays Hockey
Peter plays Soccer
Peter plays Hockey
Ola plays Soccer
Mary plays Tennis
Mary plays Soccer
Mary plays Hockey
Now I would like to create a Linq2Sql query which retrieves the following:
Get all Persons who play Hockey and Soccer
Executing the query should return: Peter and Mary
Anyone has any idea's on how to approach this in Linq2Sql?
One of the great things about Linq is that you don't HAVE to write this all as one monolithic query because it won't actually execute until you enumerate the results anyway. You could write a single query, but you don't have to. Instead, you can write this as multiple, separate queries, increasing the readability, and clarifying your intent.
var sportIds = Sports
.Where(s => s.Name == "Hockey" || s.Name == "Soccer")
.Select(s => s.Id);
var people = Person.Where(p => SportsPerPerson
.Count(spp => (spp.PersonId == p.Id)
&& sportIds.Contains(spp.SportId)) == 2);
First, we get the collection of sport Ids we're interested in. Then, we find all the people with two sports in the first list. Although it's expressed as multiple queries, Linq will compress it all into one operation for us when we finally enumerate the results.
EDIT: Here is a complete test class illustrating the query:
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace L2STest
{
public class Sport
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class SportPerPerson
{
public int Id { get; set; }
public int PersonId { get; set; }
public int SportId { get; set; }
}
[TestClass]
public class SportsTest
{
private List<Person> persons;
private List<Sport> sports;
private List<SportPerPerson> sportsPerPerson;
[TestInitialize]
public void MyTestInitialize()
{
persons = new List<Person>
{
new Person {Id = 1, FirstName = "John", LastName = "Doe"},
new Person {Id = 2, FirstName = "Peter", LastName = "Svendson"},
new Person {Id = 3, FirstName = "Ola", LastName = "Hansen"},
new Person {Id = 4, FirstName = "Marv", LastName = "Petterson"},
};
sports = new List<Sport>
{
new Sport {Id = 1, Name = "Tennis"},
new Sport {Id = 2, Name = "Soccer"},
new Sport {Id = 3, Name = "Hockey"},
};
sportsPerPerson = new List<SportPerPerson>
{
new SportPerPerson {Id = 1, PersonId = 1, SportId = 1},
new SportPerPerson {Id = 2, PersonId = 1, SportId = 3},
new SportPerPerson {Id = 3, PersonId = 2, SportId = 2},
new SportPerPerson {Id = 4, PersonId = 2, SportId = 3},
new SportPerPerson {Id = 5, PersonId = 3, SportId = 2},
new SportPerPerson {Id = 6, PersonId = 3, SportId = 1},
new SportPerPerson {Id = 7, PersonId = 4, SportId = 2},
new SportPerPerson {Id = 8, PersonId = 4, SportId = 3},
};
}
[TestMethod]
public void QueryTest()
{
var sportIds = sports
.Where(s => s.Name == "Hockey" || s.Name == "Soccer")
.Select(s => s.Id);
var people = persons.Where(p => sportsPerPerson
.Count(spp => (spp.PersonId == p.Id)
&& sportIds.Contains(spp.SportId)) == 2);
Assert.AreEqual(2, people.Count());
Assert.AreEqual("Peter", people.First().FirstName);
Assert.AreEqual("Marv", people.Last().FirstName);
}
}
}