I have two string array and want to see if there are any intersection or not. I am using linq to sql in c# and fetch the database field and compare it with the user input as below :
string[] Materials = material.Split('-');
AllItems = (from item in AllItems
where item.Material.Split(',').Intersect(Materials).Count() != 0
select item).ToList();
Materials are user input string which has - delimiter and in database I have string with , delimiter.
I wonder why the result is always null. I mean the query result says there is no intersection but I check and there is.
Another alternative query that I used and take the same result was this :
string[] Materials = material.Split('-');
HashSet<string> stringSet = new HashSet<string>(Materials);
AllItems = (from item in AllItems
where item.Color.Split(',').Where(c => stringSet.Contains(c)).Count() != 0
select item).ToList();
I am so confused whats the problem with these queries. I should mention that the strings are UTF8 one and contains 2 bytes character in persian language, I guess maybe It's the problem but I don't know how to solve it.
Is there any solutions?
UPDATE (AllItems and Example) :
List<Item> AllItems = (from item in db.Items
select item).ToList();
Example of material => "ابی-قرمز-زرد"
Example of Item.Material => "ابی,سبز"
Update (Local Test) :
I test the same linq in some local string and using linq to object and the answer is correct !!! but in linq to sql and server string it always says that nothing found ! whats the problem?
I found out that, One of the Item's Color attribute was null and cause exception and return null. so I add a check to be not null before split and it works.
thanks all of you guys.
Related
I am querying in C# for the first time, so please forgive my ignorance. I want to query a table, then place the results in an array/dict/dataframe to then be accessed later. I am unable to run the final code on my end, so this is more of an exercise in setting up the queries for when the final code (a chatbot) works.
Here is the code that should work to get boiling points and melting points seperately. Assume that casnumber is declared in advance (let's just call it str '753')
boiling_point = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.boiling_point).FirstOrDefault();
melting_point = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.metling_point).FirstOrDefault();
How would I get the results of the query to an array/dict/dataframe instead?
dict = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.boiling_point,
cdls.melting_point).FirstOrDefault();
Ideally, I would want {(boiling_point : 200F), (melting_point : 100F)} as output, or something similar in a table/df/array. There are 30+ attributes in the table, so a way to assign key-value pairs or create a dataframe from the query for each attribute queried would be ideal.
Get a list of Tuples like this
var tuples = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select (cdls.boiling_point, cdls.melting_point))
.ToList();
tuples will be a list of tuples (ex. List<(string boiling_point, string melting_point)>)
for (var tuple in tuples)
{
var boiling_point = tuple.boiling_point;
var melting_point= tuple.melting_point;
}
I am going to write search query. In that query I have a list of string like this:
var listWords=new List<string>(){"Hello","Home","dog","what"};
and also I have list of customers. How Can I search if customer's Name contains at least one of items in listWords:
Jack Home
Hot dog
what a big dog
Tried:
var prodList = events.Where(x =>listWords.IndexOf(x.Name.Trim().ToLower()) != -1).ToList();
Use .Where and .Any:
var result = events.Where(c => listWords.Any(w => c.Name.Contains(w)));
Problem with your solution is that you are converting your string to lower case but the collection of words has characters in upper case. In that case it will not find a match:
How can I make Array.Contains case-insensitive on a string array?
I am new to LINQ.
I am trying to compare 2 comma separated strings to see if they contain a matching value.
I have a string that contains a list of codes.
masterFormList = "AAA,BBB,CCC,FFF,GGG,HHH"
I am trying to compare it to a list of objects. In a given field FormCode contains a comma separated string of codes. I want to see if this at lease one code in this string is in the masterFormList.
How would I write linq to accomplish this?
Right now I have:
resultsList = (from r in resultsList
where r.FormCodes.Split(',').Contains(masterFormList)
select r).ToList();
It does not return any matching items from the list.
Please advise
You'd need to build a collection of the items to search for, then check to see if there are any contained within that set:
var masterSet = new HashSet<string>(masterFormList.Split(','));
resultsList = resultsList
.Where(r => r.FormCodes.Split(',')
.Any(code => masterSet.Contains(code)))
.ToList();
var masterFormList = "AAA,BBB,CCC,FFF,GGG,HHH";
var otherList = "XXX,BBB,YYY";
bool match = otherList.Split(',').Intersect(masterFormList.Split(',')).Any();
or if you want the matching items
var matches = otherList.Split(',').Intersect(masterFormList.Split(',')).ToList();
To answer the question as stated, this will find all the matches between two strings:
var matches =
from masterCode in masterFormList.Split(',')
join formCode in formCodes.Split(',') on masterCode equals formCode
select formCode;
foreach (string match in matches)
{
Console.WriteLine(match);
}
but that's overkill if all you want to know is that one exists. You could just do this with the same query:
Console.WriteLine(matches.Any());
However, that's likely to do more work than strictly necessary. A modification to Reed Copsey's answer might be simplest (if we're looking to answer the question in the title of your post):
var masterSet = new HashSet<string>(masterFormList.Split(','));
bool atLeastOneMatch = formCodes.Split(',').Any(c => masterSet.Contains(c));
While these are reasonably idiomatic LINQ solutions to the problem you stated ("I am trying to compare 2 comma separated strings to see if they contain a matching value") they're probably not a great match for what you actually seem to want, which is to take a list of objects, and find just the ones in which a particular property meets your criteria. And a join is probably the wrong approach for that because it looks rather unwieldy:
resultList =
(from formItem in resultList
from code in formItem.FormCodes.Split(',')
join masterCode in masterFormList.Split(',') on code equals masterCode
group code by formItem into matchGroup
select matchGroup.Key)
.ToList();
or if you prefer:
resultList =
(from formItem in resultList
from code in formItem.FormCodes.Split(',')
join masterCode in masterFormList.Split(',') on code equals masterCode into matchGroup
where matchGroup.Any()
select formItem)
.Distinct()
.ToList();
These solutions have little to commend them...
So given the problem evident from your code (as opposed to the problem defined in the question title and the first 3 paragraphs of your post), Reed Copsey's solution is better.
The one tweak I'd make is that if your master set is fixed, you'd only want to build that HashSet<string> once, to amortize the costs. So either you'd put it in a static field:
private readonly static HashSet<string> masterSet =
new HashSet<tring>(masterFormList.Split(',');
or use Lazy<T> to create it it on demand.
(Edited 8/8/2013 after Reed pointed out to me in the comments that the problem evident from the code example was not the same as the problem stated in the question.)
I need to add a literal value to a query. My attempt
var aa = new List<long>();
aa.Add(0);
var a = Products.Select(p => p.sku).Distinct().Union(aa);
a.ToList().Dump(); // LinqPad's way of showing the values
In the above example, I get an error:
"Local sequence cannot be used in LINQ to SQL implementation
of query operators except the Contains() operator."
If I am using Entity Framework 4 for example, what could I add to the Union statement to always include the "seed" ID?
I am trying to produce SQL code like the following:
select distinct ID
from product
union
select 0 as ID
So later I can join the list to itself so I can find all values where the next highest value is not present (finding the lowest available ID in the set).
Edit: Original Linq Query to find lowest available ID
var skuQuery = Context.Products
.Where(p => p.sku > skuSeedStart &&
p.sku < skuSeedEnd)
.Select(p => p.sku).Distinct();
var lowestSkuAvailableList =
(from p1 in skuQuery
from p2 in skuQuery.Where(a => a == p1 + 1).DefaultIfEmpty()
where p2 == 0 // zero is default for long where it would be null
select p1).ToList();
var Answer = (lowestSkuAvailableList.Count == 0
? skuSeedStart :
lowestSkuAvailableList.Min()) + 1;
This code creates two SKU sets offset by one, then selects the SKU where the next highest doesn't exist. Afterward, it selects the minimum of that (lowest SKU where next highest is available).
For this to work, the seed must be in the set joined together.
Your problem is that your query is being turned entirely into a LINQ-to-SQL query, when what you need is a LINQ-to-SQL query with local manipulation on top of it.
The solution is to tell the compiler that you want to use LINQ-to-Objects after processing the query (in other words, change the extension method resolution to look at IEnumerable<T>, not IQueryable<T>). The easiest way to do this is to tack AsEnumerable() onto the end of your query, like so:
var aa = new List<long>();
aa.Add(0);
var a = Products.Select(p => p.sku).Distinct().AsEnumerable().Union(aa);
a.ToList().Dump(); // LinqPad's way of showing the values
Up front: not answering exactly the question you asked, but solving your problem in a different way.
How about this:
var a = Products.Select(p => p.sku).Distinct().ToList();
a.Add(0);
a.Dump(); // LinqPad's way of showing the values
You should create database table for storing constant values and pass query from this table to Union operator.
For example, let's imagine table "Defaults" with fields "Name" and "Value" with only one record ("SKU", 0).
Then you can rewrite your expression like this:
var zero = context.Defaults.Where(_=>_.Name == "SKU").Select(_=>_.Value);
var result = context.Products.Select(p => p.sku).Distinct().Union(zero).ToList();
I'm encountering some peculiarities with LINQ to SQL.
With a relatively simple query, I want to select some fields, but have the date fields formatted as strings, which I first achieved like this:
var list = dataContext.MyLists.Single(x => x.ID == myId);
var items = from i in list.MyItems
select
new
{
i.ID,
i.Sector,
i.Description,
CompleteDate = i.CompleteDate.HasValue ? i.CompleteDate.Value.ToShortDateString() : "",
DueDate = i.DueDate.HasValue ? i.DueDate.Value.ToShortDateString() : ""
};
Later on I tried the following query, which is exactly the same, except I'm querying straight from my dataContext, rather than an element in my first query:
var items = from i in dataContext.MyLists
select
new
{
i.ID,
i.Sector,
i.Description,
CompleteDate = i.CompleteDate.HasValue ? i.CompleteDate.Value.ToShortDateString() : "",
DueDate = i.DueDate.HasValue ? i.DueDate.Value.ToShortDateString() : ""
};
The first one runs fine, yet the second query yields a:
Could not translate expression '...' into SQL and could not treat it as a local expression.
If I remove the lines that Format the date, it works fine. If I remove the .HasValue check it also works fine, until there are null values.
Any ideas?
Anthony
I'd do the SQL part without doing the formatting, then do the formatting on the client side:
var items = list.MyItems.Select(item => new { item.ID, item.Sector, item.Description,
item.CompleteDate, item.DueDate })
.AsEnumerable() // Don't do the next bit in the DB
.Select(item => new { item.ID, item.Sector, item.Description,
CompleteDate = FormatDate(CompleteDate),
DueDate = FormatDate(DueDate) });
static string FormatDate(DateTime? date)
{
return date.HasValue ? date.Value.ToShortDateString() : ""
}
In the first query, you have already got the data back from the database by the time the second line runs (var items = ...). This means that the 2nd line runs at the client, where ToShortDateString can run quite happily.
In the second query, because the select runs directly on an IQueryable collection (dataContext.MyLists), it attempts to translate the select into SQL for processing at the server, where ToShortDateString is not understood - hence the "Could Not Translate.." exception.
To understand this a bit better, you really need to understand the difference between IQueryable and IEnumerable, and at which point a Linq To Sql query stops being IQueryable and becomes IEnumerable. There is plenty of stuff on the web about this.
Hope this helps,
Paul
Just like the error message tells you, the difference is due to what can be done locally verses remotely while connecting to SQL.
The Linq code has to be converted by Linq to SQL into a SQL command for the remote data pulls - anything that has to be done locally cannot be included.
Once you pulled it into a local object (in the first example), it is not using Linq to SQL anymore, just plain Linq. At that point you are free to do local manipulations on it.
Maybe there was a copy and paste error or just a typo in your sample. But if not, this might be the problem...
In the second query you are querying a collection of lists, whereas in the first query you were querying the items within a list. But you haven't adjusted the query to account for this difference.
What you need might be this. Note the commented lines which did not appear in your second sample.
var items = from aList in dataContext.MyLists
from i in aList.MyItems // Access the items in a list
where aList.ID == myId // Use only the single desired list
select
new
{
i.ID,
i.Sector,
i.Description,
CompleteDate = i.CompleteDate.HasValue ? i.CompleteDate.Value.ToShortDateString() : "",
DueDate = i.DueDate.HasValue ? i.DueDate.Value.ToShortDateString() : ""
};
ToShortDateString() is not supported by Linq to SQL http://msdn.microsoft.com/en-us/library/bb882657.aspx