I have a string str = "abc,def,ghi". The length of string will vary. There could be one or more values separated by comma.
I have an object that has a property Code that is string and can contain values such as - "abc, stu, xyz"
I'm trying to filter objects from a collection that will return only those that contain a string in str
So, if object.Code = "abc, stu, xyz" and string str = "abc,def,ghi" then return the object.
objects.Where( x => x.Code.Split(',').Any(s => (???)) );
where ??? is where my string str values will come in.
Thanks,
var result = objects.Where(x => x.Code.Split(',').Any(s => (str.Split(',').Any(f => f.Equals(s)))));
Conversion of the str to a HashSet will improve the testing speed and simplify the query, but perhaps is overkill if your objects only have a few entries. I assume the Code property does not have spaces after each comma.
var strHash = str.Split(',').ToHashSet();
var ans = objects.Where(o => o.Code.Split(',', StringSplitOptions.RemoveEmptyEntries).Any(c1 => strHash.Contains(c1)));
Related
Please help on converting a list of objects got from DB into substrings separated by a comma
Take for example I have a sample code below:
List<string> CategoryNames = new List<string>();
CategoryNames.Add("myName1");
CategoryNames.Add("myName2");
CategoryNames.Add("myName3");
I want to convert CategoryNames into a format like this
"myName1","myName2","myName3"
From the above CatgoryNames happen to be retrieved from db.
var categoryNames = _context.BillingCategory.ToList();
How do I convert the categoryNames into substrings as shown above?
Any help will be appreciated.
You can use String.Join() method by combining with LINQ for preserving the quotes before joining:
var result = String.Join(",", CategoryNames.Select(item => $"\"{item}\""));
And here is the clearer version of the code if you don't linke singleliner:
var QuotedCategroyNames = CategoryNames
.Select(item => $"\"{item}\"");
var result = String.Join(",", QuotedCategroyNames);
Use LINQ Select to enclose all names in quotes, then string.Join to merge back into a comma separated string.
string.Join(',', CategoryNames.Select(n => '"' + n + '"'));
You can use string.Join() and concat with the double quotes character :
var serialized = $#"""{ string.Join(#""",""", CategoryNames) }"""; // "myName1","myName2","myName3"
Try it yourself
Problem
Background Story: I am rewriting all SQL queries of legacy system into LINQ.
The database is not as clean as I expect. As many of these SQL record contains spaces or different cases which treated as the same.
SELECT *
FROM fruit
WHERE name = #fruitname;
Provided #fruitname is apple, this query will match any record ends with apple, _apple, APPLE_ (where _ is a whitespace character).
However, This is the expected behavior in my use cases.
On the otherhand, LINQ string comparison is more precise. Which annoys me because such issues keep surfacing to me.
Setup
FruitTableAdapter fruitsAdapter = new FruitTableAdapter();
MyGardenDataSet.FruitDataTable fruitsTable = fruitsAdapter.GetData();
Approaches
// Issue 1: Does not match, '_apple' or 'APPLE_'
var fruits1 = fruitsTable.Where(row=>row.name == fruitname);
// Issue 2: String Comparison with case insensitive (does not match 'APPLE')
var fruits2 = fruitsTable.Where(
row=>row.nameEquals(fruitname, StringComparison.OrdinalIgnoreCase));
// Issue 3: Trailing space with case insensitive
var fruits2 = fruitsTable.Where(
row=>row.name.Trim().Equals(fruitname.Trim(),
StringComparison.OrdinalIgnoreCase));
I'm not sure but there could be many issues which SQL query are different from String Comparison.
Is there any SQL aware StringComparison? How can I achieve the same string comparison as SQL in LINQ?
Here's a nice String Extension method that builds on the solutions from a similiar question about casing StackOverflow
Keep in mind, we want to allow for NULL strings in our trim scenarios, so this extension will do a Case Insensitive compare on Trimmed strings after checking for null values
public static class StringExtension
{
// Trim strings and compare values without casing
public static bool SqlCompare(this string source, string value)
{
// Handle nulls before trimming
if (!string.IsNullOrEmpty(source))
source = source.Trim();
if (!string.IsNullOrEmpty(value))
value = value.Trim();
// Compare strings (case insensitive)
return string.Equals(source, value, StringComparison.CurrentCultureIgnoreCase);
}
}
Here's how to use the Extension in your LINQ statement:
(SysUserDisplayFavorites table is composed of char() fields with space filled results. These will get trimmed and compared (case insensitive) to the user provided values in displayFavorite object)
var defaultFavorite = _context.SysUserDisplayFavorites
.Where(x => x.UserId.SqlCompare(displayFavorite.UserId))
.Where(x => x.ModuleCode.SqlCompare(displayFavorite.ModuleCode))
.Where(x => x.ActivityCode.SqlCompare(displayFavorite.ActivityCode))
.Where(x => x.ActivityItemCode.SqlCompare(displayFavorite.ActivityItemCode))
.Where(x => x.IsDefault);
This is a very late answer.
You can use Regex to solve your problem
Here's what I have tried, hope it helps
I created a sample class
public class SampleTable
{
public string Name { get; set; }
public SampleTable(string name)
{
Name = name;
}
}
Populated sample data
List<SampleTable> sampleTblList = new List<SampleTable>();
sampleTblList.Add(new SampleTable(" Apple"));
sampleTblList.Add(new SampleTable(" APPLE"));
sampleTblList.Add(new SampleTable("Apple"));
sampleTblList.Add(new SampleTable("apple"));
sampleTblList.Add(new SampleTable("apple "));
sampleTblList.Add(new SampleTable("apmangple"));
Solution:-
string fruitName = "apple";
List<SampleTable> sortedSampleTblList = sampleTblList.Where(x =>
Regex.IsMatch(fruitName, x.Name, RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase)).ToList();
Output:-
string ans = String.Join(",", sortedSampleTblList.Select(x => x.Name.Replace(" ","_")).ToArray());
Console.Write(ans);
_Apple,_APPLE,Apple,apple,apple_
fruitsTable.Where(row => row.name.Trim().Equals(fruitname, StringComparison.OrdinalIgnoreCase)); should do what you need, but I'm confused because you've listed almost the same under Issue 3. Were you not realising it was working because you are reusing fruits2?
This little NUnit test is passing
[Test]
public void FruitTest()
{
var fruitsTable = new List<string> { " Apple", " APPLE", "Apple", "apple", "apple ", " apple", "APPLE " };
var fruitname = "apple ".Trim();
var fruits = fruitsTable.Where(row => row.Trim().Equals(fruitname, StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(fruitsTable.Count(), fruits.Count());
}
I have a string like this:
RoleId,RoleName|CategoryId,CategoryName
I split them first like this:
string delm = "RoleId,RoleName|CategoryId,CategoryName";
string[] FieldsToReplace = attributes[0].IdsToReplaceWith.Split('|');
Suppose i have a variable in which i have RoleId:
string test = "RoleId";
Now what i am trying to get each the array item in which has string RoleId, i don't want to use contains i need exact match.
I have tried this query:
var test = FieldsToReplace
.Where(x=>FieldsToReplace
.All(y => y.Split(',').Equals(delm))).ToArray();
i can harcode like this for first index:
var IdProperty = FieldsToReplace.FirstOrDefault(x => x.Split(',')[0] == delm);
but i want it dynamic so it check each item of array which i got after , split.
but it returns no record.
Any help will be appreciated.
You want to split on your elements of the array. Besides that it seems appropriate to check if any element of these splitted ones are equal to your comparison string:
var test =
FieldsToReplace
.Where(x => x.Split(',')
.Any(y => y.Equals(prop.Name)))
.ToArray();
Hi I am looking for a simple way to et just the name after the CN value
CN=Andrew Adams,OU=Services,OU=Users,OU=GIE,OU=CSP,OU=STAFF,DC=example,DC=net
is there an easy way to do this? I am currently doing this:
ResultPropertyValueCollection manager = result.Properties["manager"];
string managerUserName = manager[0].ToString();
string[] managerNameParts = managerUserName.Split(',');
string managerName = managerNameParts[0].Substring(4);
Console.WriteLine("Manager Name:" + managerName);
but it feels kind of bad.
This is a great place to use Regular Expressions. Try this:
var text = "CN=Andrew Adams,OU=Services,OU=Users,OU=GIE,OU=CSP,OU=STAFF,DC=example,DC=net";
var match = Regex.Match(text, #"CN=([^,]+)");
if (match.Success) return match.Groups[0].Value;
The expression CN=([^,]+) will look for the text CN= followed by one or more non-commas, and will stick that part of it into Groups[0].
You can do this:
var name = "CN=Andrew Adams,OU=Services,OU=Users,OU=GIE,OU=CSP,OU=STAFF,DC=example,DC=net"
.Split(',')[0].Split('=')[1];
Demo
What it does is splits on , and takes the first element and then splits it by = and takes the second element.
If you cannot have the same format, you can do a regex:
Regex.Match(name,#"(?<=CN=)[^,]+").Value;
Another option, using LINQ.
If the name/value pair exists anywhere in the string, you'll get it; if not, managerName will be null.
var managerName = input.Split(',')
.Where(x => x.StartsWith("CN="))
.Select(x => x.Split('=')[1])
.SingleOrDefault();
I find doing it like this fairly easy to read:
var input = #"CN=Andrew Adams,OU=Services,OU=Users,OU=GIE,OU=CSP,OU=STAFF,DC=example,DC=net";
var items = input.Split(',');
var keyValues = items.Select(x =>
{
var split = x.Split('=');
return new { Key = split[0], Value = split[1] };
});
var managerName = keyValues.Single(x => x.Key == "CN").Value;
I try to filter my items according to unknown number of filters.
//item.statusId is nullable int
//statusIds is a string
{...
var statusIds = Convert.ToString(items["StatusId"]);//.Split(';');
results = mMaMDBEntities.MamConfigurations.Where(item =>
FilterByStatusId(statusIds, item.StatusId)).ToList();
}
return results;
}
private bool FilterByStatusId(string statusIds, int? statusId)
{
return statusIds.Contains(statusId.ToString());
}
But I get this error:
LINQ to Entities does not recognize the method 'Boolean FilterByStatusId(System.String, System.Nullable1[System.Int32])' method, and this method cannot be translated into a store expression.`
Any idea how to re-write it?
If statusIds is an array then you can do:
results = mMaMDBEntities.MamConfigurations
.Where(item => statusIds.Contain(item.StatusID)).ToList();
Some what similar to SQL Select * from table where ID in (1,2,3)
EDIT:
From your code it appears you have a string with semicolon separated values. You can try the following to get an array of int and later use that in your LINQ expression.
var str = Convert.ToString(items["StatusId"]);//.Split(';');
// string str = "1;2;3;4;5"; //similar to this.
int temp;
int[] statusIds = str.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => int.TryParse(r, out temp) ? temp : 0)
.ToArray();
then later you can use the int array in your expression like:
results = mMaMDBEntities.MamConfigurations
.Where(item => statusIds.Contain(item.StatusID)).ToList();
Why not insert the predicate statement directly into the where clause?
like this:
results = mMaMDBEntities.MamConfigurations.Where(item => statusIds.Contains(item.StatusId).ToList();
you might need to convert the string array resulting from the Split to a List or IEnumerable to make this work.
The exception is pretty self-explanatory, the method cannot be converted to a SQL statement in the form you wrote it, but if you write it like above, you should obtain the same result and it will work.