how to use Contains in where clause in linq - c#

I have this:
var myResult = uow.GetRepository<SLItemsCustomersCard, long>()
.Query(x => x.CustomerId == customerId && x.SquareColor == squareColor)
.OrderBy(x => x.BranchMapRang)
.Select((r, i) => new { Row = r, Index = i })
.Where(x => x.Index == visitCounter - 1).ToList();
but I want to achive this in where clause:
.Where(x => x.Index.Cotains(visitCounter)).ToList();
How to do this?

You seem to be misunderstanding what the Contains method does. I'm basing this answer on your earlier usage of:
Where(x => x.Index == visitCounter - 1)
In other words, visitCounter is an integer (and so is Index). But then you want to use it like this:
Where(x => x.Index.Contains(visitCounter))
Which does not make syntactical sense. An integer (Index) does not have a Contains function. It's not fully clear to me what you are trying to achieve, but your comment clarifies it a bit more:
But I want to achieve something like IN clause in SQL server.
The IN clause in SQL requires a range of possibilities (a list of integers, in your case), and you're not working with a list of integers here. Furthermore, you have phrased it as Index.Contains(visitCounter) which would imply that you're expecting Index to be the list of integers?
That simply doesn't make sense. So I'll give you the answer that makes the most sense, on the assumption that you weren't accurate with your pseudocode:
List<int> visitorIds = new List<int>() { 1, 5, 99, 125 };
And then you can do the following:
.Where(x => visitorIds.Contains(x.Index))
To put it in words, this snippet basically tells the computer to "only give the items whose Index is mentioned in the visitorIds list".

You can use Contains like this:
int[] VisitorIds = new int[] {1,2,3}; //an array to check with
.Where(x => vivitorIds.Contains(x.Index)).ToList();

Related

Why isn't this LINQ parsing a file properly?

I have a file with a simple key,value format, one per line.
e.g:
word1,filepath1
word2,filepath2
word3,filepath5
I'm trying to read this into a Dictionary<string,string> in one go with LINQ. There are some duplicates in the file (where the first part - the first string - is the duplicate). In this case, I'm ok with dropping the duplicates.
This is my LINQ which isn't working:
var indexes = File.ReadAllLines(indexFileName)
.Select(x => x.Split(','))
.GroupBy(x=>x[0])
.ToDictionary(x => x.Key, x => x.ElementAt(1));
The ToDictionary part is confusing me, how do I retrieve the first value from the group and assign it to the value of the dictionary?
I get a System.ArgumentOutOfRangeException: 'Specified argument was out of the range of valid values.' exception.
var indexes = File.ReadAllLines(indexFileName)
.Select(x => x.Split(','))
.GroupBy(x => x[0])
.ToDictionary(x => x.Key, x => x.First()[1]);
So the problem here is that you're grouping arrays, not strings. Therefore the group objects you're dealing with in the ToDictionary() lambda are enumerations of arrays, not of strings. g.ElementAt(0) isn't a string. It's the first array of strings:
When
g.Key == "word1"
then g.ElementAt(0) is...
{ "word1", "filepath1" }
So you want g.ElementAt(0).ElementAt(1), or g.First()[0], or something to that effect.
That seems painfully obvious in hindsight, but unfortunately only in hindsight, for me.
I would suggest that after you accept Matthew Whited's answer, you clarify the code by turning the split lines into anonymous objects as soon as you can. ElementAt(1) doesn't communicate much.
var indexes =
File.ReadAllLines(indexFileName)
.Where(s => !String.IsNullOrEmpty(s))
.Select(x => x.Split(','))
// Turn the array into something self-documenting
.Select(a => new { Word = a[0], Path = a[1] })
.GroupBy(o => o.Word)
.ToDictionary(g => g.Key, g => g.First().Path)
;
Converting each line to an object makes it easier for me to think about, and Intellisense starts playing on your team as well.

How to concatenate result of GroupBy using Linq

Let say you have list of items and you want to partition them, make operation on one partition and concatenate partitions back into list.
For example there is list of numbers and I want to partition them by parity, then reverse odds and concatenate with evens. [1,2,3,4,5,6,7,8] -> [7,5,3,1,2,4,6,8]
Sounds simple, but I've got stuck on merging back two groups. How would you do it with LINQ?
IEnumerable<int> result = Enumerable.Range(0, 1000)
.GroupBy(i => i % 2)
.Select(p => p.Key == 1 ? p.Reverse() : p)
.??? // need to concatenate
Edit
[1,2,3] is the representation of array which I want to get as the result, not output, sorry if I confused you by that.
The GroupBy method returns an IEnumerable<IGrouping<TKey, TSource>>. As IGrouping implements IEnumerable, you can use SelectMany to concatenate multiple IEnumerable<T> instances into one.
Enumerable.Range(0, 1000)
.GroupBy(i => i % 2)
.Select(p => p.Key == 1 ? p.Reverse() : p)
.OrderByDescending(p => p.Key)
.SelectMany(p => p);
There are a few ways to achieve this,
so if we start with your function
Enumerable.Range(0, 1000)
.GroupBy(i => i % 2)
.Select(p => p.Key == 1 ? p.Reverse() : p)
you could then use an Aggregate
.Aggregate((aggrgate,enumerable)=>aggrgate.Concat(enumerable))
this will then go though your list of results and concat them all into a collection and return it, you just need to make sure that aggrgate and enumerable are the same type in this case a IEnumerable<int>
another would be to call SelectMany()
.SelectMany(enumerable=>enumerable)
this then likewise pulls all the enumerables together into a single enumerable, again you need to ensure the types are IEnumerable<int>
other options would be to hard code the keys as Tim is suggesting or pull out of linq and use a loop
You could use this approach using a Lookup<TKey, TElement>:
var evenOddLookup = numbers.ToLookup(i => i % 2);
string result = String.Join(",", evenOddLookup[1].Reverse().Concat(evenOddLookup[0]));
If you don't want a string but an int[] as result:
int[] result = evenOddLookup[1].Reverse().Concat(evenOddLookup[0]).ToArray();
You could do something like this.
var number = string.Join(",",
Enumerable.Range(0, 1000)
.GroupBy(i => i % 2) // Separate even/odd numbers
.OrderByDescending(x=>x.Key) // Sort to bring odd numbers first.
.SelectMany(x=> x.Key ==1? // Sort elements based on even or odd.
x.OrderByDescending(s=>s)
: x.Where(s=> s!=0).OrderBy(s=>s))
.ToArray());
string output = string.Format("[{0}]", number);
Check this Demo
Just use OrderBy like this:
List<int> arr = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
var result = arr.OrderBy(i => i % 2 == 0 ? 1 : 0)
.ThenBy(i => i % 2 == 0 ? i : int.MaxValue)
.ThenByDescending(i => i);
This should give you your desired result as you want:
[1,2,3,4,5,6,7,8] will be converted into [7,5,3,1,2,4,6,8]

If number have no value it should placed last(LINQ)

I am using linq to sql and my code looks like this:
var agendaLists =
dataContext.view_Agendas.Where(m => m.MeetingID == meetingID)
.OrderBy(n => n.Number)
.ThenBy(n => n.CaseNumber)
.ThenByDescending(s => s.MainYN)
.ToList();
So basicly our "n.Number" is the order number. everything works fine its sorted 1,2,3,4 etc which is correct. but if a object have no value in n.Number it will be displayed in the top but I want it to be placed last.
Today it sorts like this, lets say we get 4 objects back:
Null, 1, 2, 3
I want it sorted like this:
1, 2, 3, Null
Any kind of help is appreciated.
try the following:
n => n.Number ?? int.MaxValue
I dont remember if you actually have to check for DBNull, but it would be the same.
You can use this approach, presuming Number is an int?:
var agendaLists = dataContext.view_Agendas
.Where(m => m.MeetingID == meetingID)
.OrderBy(m => n.Number.HasValue ? 0 : 1)
.ThenBy(n => n.Number)
.ThenBy(n => n.CaseNumber)
.ThenByDescending(s => s.MainYN)
.ToList();

Order By on the Basis of Integer present in string

I've a problem in my C# application... I've some school classes in database for example 8-B, 9-A, 10-C, 11-C and so on .... when I use order by clause to sort them, the string comparison gives results as
10-C
11-C
8-B
9-A
but I want integer sorting on the basis of first integer present in string...
i.e.
8-B
9-A
10-C
11-C
hope you'll understand...
I've tried this but it throws exception
var query = cx.Classes.Select(x=>x.Name)
.OrderBy( x=> new string(x.TakeWhile(char.IsDigit).ToArray()));
Please help me... want ordering on the basis of classes ....
Maybe Split will do?
.OrderBy(x => Convert.ToInt32(x.Split('-')[0]))
.ThenBy(x => x.Split('-')[1])
If the input is well-formed enough, this would do:
var maxLen = cx.Classes.Max(x => x.Name.Length);
var query = cx.Classes.Select(x => x.Name).OrderBy(x => x.PadLeft(maxLen));
You can add 0 as left padding for a specified length as your data for example 6
.OrderBy(x => x.PadLeft(6, '0'))
This is fundamentally the same approach as Andrius's answer, written out more explicitly:
var names = new[] { "10-C", "8-B", "9-A", "11-C" };
var sortedNames =
(from name in names
let parts = name.Split('-')
select new {
fullName = name,
number = Convert.ToInt32(parts[0]),
letter = parts[1]
})
.OrderBy(x => x.number)
.ThenBy(x => x.letter)
.Select(x => x.fullName);
It's my naive assumption that this would be more efficient because the Split is only processed once in the initial select rather than in both OrderBy and ThenBy, but for all I know the extra "layers" of LINQ may outweigh any gains from that.

Chained selects with where at the end

Given following structure: a person has functions. Each function has roles. Each roles has features. Now I would like to figure out with linq if a given person has a certain feature, but I am doing something wrong with this query. As a result I always get the count of the functions (but I'd like to get the count of the features):
var count = person.Functions
.Select(fu => fu.Roles
.Select(r => r.Features
.Where(f => f.FeatureId == 99999)))
.Count();
What am I doing wrong here? According to this query I expect either 0 (hasn't got the feature) or 1.
var query = from function in person.Functions
from role in function.Roles
from feature in role.Features
where feature.FeatureId == 99999
select feature;
var count = query.Count();
or
var count = person.Functions
.SelectMany(function => function.Roles)
.SelectMany(role => role.Features)
.Count(feature => feature.FeatureId == 99999);
If you don't need the exact count but just want to know if the person has the feature or not, use Any instead of Count.
var count = person.Functions
.SelectMany(p => p.Roles)
.SelectMany(r => r.Features)
.Where(f => f.FeatureId == 99999)
.Count();
I'm not really sure, but I think you want the total number of Features with teh given Id. You would want to use SelectMany.

Categories

Resources