Select record where value equals value of id - linq

This is a simple but hard to describe question
await dbContext.MyTable.AnyAsync(x => x.valueOne == valueOne && x.valueTwo == /*here's my problem*/ );
valueOne is getting passed in as a parameter. The end of the statement in pseudocode would be:
x.valueTwo == the valueTwo of valueOne's record
I know I could pull in valueOne's record and compare from there, but that's clumsier and I feel like there's definitely a better way if only I could find it.
How can I do this in one line?
Edit: clarification
To clarify, the clumsy way would be
var valueOneRecord = await dbContext.MyTable.FirstAsync(x => x.valueOne == valueOne);
exists = await dbContext.MyTable.AnyAsync(x => x.valueOne == valueOne && x.valueTwo == valueOneRecord.valueTwo);
I'm trying to merge this into one line instead of having two database requests

Please try the below
dbContext.MyTable.Join(dbContext.MyTable,
x => new {
x.valueOne,
valueTwo = x.valueOne
},
y => new {
y.valueOne,
y.valueTwo
},
(x, y) => new
{
record1_valueOne = x.valueOne,
record1_valueTwo = x.valueTwo,
record2_valueOne = y.valueOne,
record2_valueTwo = y.valueTwo,
}).Where(x => x.record1_valueOne == valueOneParam && x.record2_valueOne == valueOneParam);

Quite often it is easier for us if you give us your requirement instead of giving us some code and say that the code is not working.
Let's assume that your clumsy method is what you want.
So MyTable is a sequence of objects, let's call them Values. Every Value has at least two properties: ValueOne and ValueTwo. You also have an input value: valueOne.
Suppose you had Schools and Students, every School had a primary key in Id, and a State
class School
{
public int Id {get; set;}
public int CityId {get; set;}
...
}
public class Student
{
public int Id {get; set;}
public string Name {get; set;}
public int CityId {get; set;}
}
A note so strange query would be:
Give me all Students that live in the same City as School 10
int schoolId = 10;
var studentsInSameCityAsSchool10 = dbContext.Schools
// keep only school with Id == 10
.Where(school => school.Id == 10)
// get all Students on these Schools
.GroupJoin(dbContext.Students,
school => school.CityId,
student => student.CityId,
(school, studentsWithSameCityId) => new
{
SchoolId = school.Id,
Students = studentsWithSameCityId.Select(student => new
{
StudentId = student.Id,
Name = student.Name,
...
})
.ToList(),
});
Very straightforward, isn't it. Now let's do a query in just one table:
Give me all Schools with the same CityId as School [10]
int schoolId = 10;
var studentsInSameCityAsSchool10 = dbContext.Schools
// keep only school with Id == 10
.Where(school => school.Id == 10)
// get all Students on these Schools
.GroupJoin(dbContext.Students,
school => school.CityId,
student => student.CityId,
(school, studentsWithSameCityId) => new
{
SchoolId = school.Id,
Students = studentsWithSameCityId.Select(student => new
{
StudentId = student.Id,
Name = student.Name,
...
})
.ToList(),
});
Very straightforward, isn't it. Now let's do a query in just one table:
Give me all Schools with the same CityId as School [10]
int schoolId = 10;
var studentsInSameCityAsSchool10 = dbContext.Schools
// keep only school with Id == 10
.Where(school => school.Id == 10)
// get all Students on these Schools
.Join(dbContext.Students, // Join Schools and Students
school => school.CityId, // from every School take the CityId
student => student.CityId, // from every Student take the CityId
(school, studentWithSameCityId) => new // from every School and every Student
{ // that has the same CityId, make one new
SchoolId = school.Id,
CityId = school.CityId,
StudentThatLiveInCityId = studentWithSameCityId,
});
Very straightforward, isn't it? Now let's do a query in just one table:
Give me all Schools with the same CityId as School [10]
int schoolId = 10;
var studentsInSameCityAsSchool10 = dbContext.Schools
.Where(school => school.Id == 10)
// get all Schools in the same City as School[10]
.Join(dbContext.Schools, // Join Schools and Schools
school1 => school1.CityId, // from every School1 take the CityId
school2 => school2.CityId, // from every School2 take the CityId
(school1, school2WithSameCityId) => new // from every School and every School
{ // that has the same CityId, make one new
...
});
But what does this have to do with my question
Now let's change some of the property names:
class School
{
public int ValueOne {get; set;} // was Id
public int ValueTwo {get; set;} // was CityId
}
int valueOne = 10; // was schoolId
Give me all Schools that have the same ValueTwo (was: located in the same City, or has same cityId) as School with ValueOne == valueOne (was: as School [10])
After the exercizes with Schools and Students this one should be easy:
int valueOne = 10;
var valuesWithSameValueTwo = dbContext.Schools
.Where(value => value.ValueOne == 10)
// get all Values with same ValueTwo Value[10]
.Join(dbContext.Schools, // Join Schools and Schools
val1 => val1.ValueTwo, // from every val1 take the ValueTwo
val2 => val2.ValueTwo, // from every val2 take the ValueTwo
(val, valWithSameValueTwoId) => new
{
...
});
Well, your query is easier: you only want to know if there is any such element. So you don't need to select any properties, and you can stop as soon as you've found one:
// Where and Join:
...
(val, valWithSameValueTwoId) => valWithSameTwoId)
.Any();

Related

LINQ DistinctBy chosing what object to keep

If I have a list of objects and I don't want to allow duplicates of a certain attribute of the objects. My understanding is that I can use DistinctBy() to remove one of the objects. My question is, how do I choose which of the objects with the same value of an attribute value do I keep?
Example:
How would I go about removing any objects with a duplicate value of "year" in the list tm and keep the object with the highest value of someValue?
class TestModel{
public int year{ get; set; }
public int someValue { get; set; }
}
List<TestModel> tm = new List<TestModel>();
//populate list
//I was thinking something like this
tm.DistinctBy(x => x.year).Select(x => max(X=>someValue))
You can use GroupBy and Aggregate (there is no MaxBy built-in method in LINQ):
tm
.GroupBy(tm => tm.year)
.Select(g => g.Aggregate((acc, next) => acc.someValue > next.someValue ? acc : next))
User the GroupBy followed by the SelectMany/Take(1) pattern with an OrderBy:
IEnumerable<TestModel> result =
tm
.GroupBy(x => x.year)
.SelectMany(xs =>
xs
.OrderByDescending(x => x.someValue)
.Take(1));
Here's an example:
List<TestModel> tm = new List<TestModel>()
{
new TestModel() { year = 2020, someValue = 5 },
new TestModel() { year = 2020, someValue = 15 },
new TestModel() { year = 2019, someValue = 6 },
};
That gives me:

Comparing two lists with multiple conditions

I have two different lists of same type. I wanted to compare both lists and need to get the values which are not matched.
List of class:
public class pre
{
public int id {get; set;}
public datetime date {get; set;}
public int sID {get; set;}
}
Two lists :
List<pre> pre1 = new List<pre>();
List<pre> pre2 = new List<pre>();
Query which I wrote to get the unmatched values:
var preResult = pre1.where(p1 => !pre
.any(p2 => p2.id == p1.id && p2.date == p1.date && p2.sID == p1sID));
But the result is wrong here. I am getting all the values in pre1.
Here is solution :
class Program
{
static void Main(string[] args)
{
var pre1 = new List<pre>()
{
new pre {id = 1, date =DateTime.Now.Date, sID=1 },
new pre {id = 7, date = DateTime.Now.Date, sID = 2 },
new pre {id = 9, date = DateTime.Now.Date, sID = 3 },
new pre {id = 13, date = DateTime.Now.Date, sID = 4 },
// ... etc ...
};
var pre2 = new List<pre>()
{
new pre {id = 1, date =DateTime.Now.Date, sID=1 },
// ... etc ...
};
var preResult = pre1.Where(p1 => !pre2.Any(p2 => p2.id == p1.id && p2.date == p1.date && p2.sID == p1.sID)).ToList();
Console.ReadKey();
}
}
Note:Property date contain the date and the time part will be 00:00:00.
I fixed some typos and tested your code with sensible values, and your code would correctly select unmatched records. As prabhakaran S's answer mentions, perhaps your date values include time components that differ. You will need to check your data and decide how to proceed.
However, a better way to select unmatched records from one list compared against another would be to utilize a left join technique common to working with relational databases, which you can also do in Linq against in-memory collections. It will scale better as the sizes of your inputs grow.
var preResult = from p1 in pre1
join p2 in pre2
on new { p1.id, p1.date, p1.sID }
equals new { p2.id, p2.date, p2.sID } into grp
from item in grp.DefaultIfEmpty()
where item == null
select p1;

Concert tabular data into Objects through LINQ

StudentId Name AddResss
1 A ABC
1 A XYZ
How Can i convert above result into List of following Objects
Class Result {
int StudentId {get;set;}
List<String> Address {get;set;}
}
Basically need to group by on studentId
studentList.GroupBy(x => x.StudentId)
.Select(x => new Result
{
StudentId = x.Key,
Address = x.Select(y => y.AddResss).ToList()
});
var results =
from row in table
group row.Address by new { row.StudentId, row.Name } into g
select new Result { StudentId = g.Key.StudentId, Addresses = g.ToList() };

Find / Count Redundant Records in a List<T>

I am looking for a way to identify duplicate records...only I want / expect to see them.
So the records aren't duplicated completely but the unique fields I am unconcerned with at this point. I just want to see if they have made X# payments of the exact same amount, via the exact same card, to the exact same person. (Bogus example just to illustrate)
The collection is a List<> further whatever X# is the List<>.Count will be X#. In other words all the records in the list match (again just the fields I am concerned with) or I will reject it.
The best I can come up with is to take the first record get value of say PayAmount and LINQ the other two to see if they have the same PayAmount value. Repeat for all fields to be matched. This seems horribly inefficient but I am not smart enough to think of a better way.
So any thoughts, ideas, pointers would be greatly appreciated.
JB
Something like this should do it.
var duplicates = list.GroupBy(x => new { x.Amount, x.CardNumber, x.PersonName })
.Where(x => x.Count() > 1);
Working example:
class Program
{
static void Main(string[] args)
{
List<Entry> table = new List<Entry>();
var dup1 = new Entry
{
Name = "David",
CardNumber = 123456789,
PaymentAmount = 70.00M
};
var dup2 = new Entry
{
Name = "Daniel",
CardNumber = 987654321,
PaymentAmount = 45.00M
};
//3 duplicates
table.Add(dup1);
table.Add(dup1);
table.Add(dup1);
//2 duplicates
table.Add(dup2);
table.Add(dup2);
//Find duplicates query
var query = from p in table
group p by new { p.Name, p.CardNumber, p.PaymentAmount } into g
where g.Count() > 1
select new
{
name = g.Key.Name,
cardNumber = g.Key.CardNumber,
amount = g.Key.PaymentAmount,
count = g.Count()
};
foreach (var item in query)
{
Console.WriteLine("{0}, {1}, {2}, {3}", item.name, item.cardNumber, item.amount, item.count);
}
Console.ReadKey();
}
}
public class Entry
{
public string Name { get; set; }
public int CardNumber { get; set; }
public decimal PaymentAmount { get; set; }
}
The meat of which is this:
var query = from p in table
group p by new { p.Name, p.CardNumber, p.PaymentAmount } into g
where g.Count() > 1
select new
{
name = g.Key.Name,
cardNumber = g.Key.CardNumber,
amount = g.Key.PaymentAmount,
count = g.Count()
};
You're unique entries are based off of the 3 criteria of Name, Card Number, and Payment Amount so you group by them and then use .Count() to count how many of those unique values exist. where g.Count() > 1 filters the group to duplicates only.

Linq to CSV select by column value

I know I have asked this question in a different manner earlier today but I have refined my needs a little better.
Given the following csv file where the first column is the title and there could be any number of columns;
year,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017
income,1000,1500,2000,2100,2100,2100,2100,2100,2100,2100
dividends,100,200,300,300,300,300,300,300,300,300
net profit,1100,1700,2300,2400,2400,2400,2400,2400,2400,2400
expenses,500,600,500,400,400,400,400,400,400,400
profit,600,1100,1800,2000,2000,2000,2000,2000,2000,2000
How do I select the profit value for a given year? So I may provide a year of say 2011 and expect to get the profit value of 2000 back.
At the moment I have this which shows the profit value for each year but ideally I'd like to specify the year and get the profit value;
var data = File.ReadAllLines(fileName)
.Select(
l => {
var split = l.Split(",".ToCharArray());
return split;
}
);
var profit = (from p in data where p[0] == profitFieldName select p).SingleOrDefault();
var years = (from p in data where p[0] == yearFieldName select p).FirstOrDefault();
int columnCount = years.Count() ;
for (int t = 1; t < columnCount; t++)
Console.WriteLine("{0} : ${1}", years[t], profit[t]);
I've already answered this once today, but this answer is a little more fleshed out and hopefully clearer.
string rowName = "profit";
string year = "2011";
var yearRow = data.First();
var yearIndex = Array.IndexOf(yearRow, year);
// get your 'profits' row, or whatever row you want
var row = data.Single(d => d[0] == rowName);
// return the appropriate index for that row.
return row[yearIndex];
This works for me.
You have an unfortunate data format, but I think the best thing to do is just to define a class, create a list, and then use your inputs to create objects to add to the list. Then you can do whatever querying you need to get your desired results.
class MyData
{
public string Year { get; set; }
public decimal Income { get; set; }
public decimal Dividends { get; set; }
public decimal NetProfit { get; set; }
public decimal Expenses { get; set; }
public decimal Profit { get; set; }
}
// ...
string dataFile = #"C:\Temp\data.txt";
List<MyData> list = new List<MyData>();
using (StreamReader reader = new StreamReader(dataFile))
{
string[] years = reader.ReadLine().Split(',');
string[] incomes = reader.ReadLine().Split(',');
string[] dividends = reader.ReadLine().Split(',');
string[] netProfits = reader.ReadLine().Split(',');
string[] expenses = reader.ReadLine().Split(',');
string[] profits = reader.ReadLine().Split(',');
for (int i = 1; i < years.Length; i++) // index 0 is a title
{
MyData myData = new MyData();
myData.Year = years[i];
myData.Income = decimal.Parse(incomes[i]);
myData.Dividends = decimal.Parse(dividends[i]);
myData.NetProfit = decimal.Parse(netProfits[i]);
myData.Expenses = decimal.Parse(expenses[i]);
myData.Profit = decimal.Parse(profits[i]);
list.Add(myData);
}
}
// query for whatever data you need
decimal maxProfit = list.Max(data => data.Profit);

Resources