Take objects which attributes contains any element of array - c#

I want to take those members whose name contains at least one of strings in array.
string[] words=content.TrimEnd().TrimStart().Split(' ');
So I want to choose that members which names contains any string from these words array, something like this
context.Members.Where(p.Name.Contains(word))
Also, I can't write Contains in LINQ expression, because it can't parse it to SQL. Which would i write in Where statement?

A potentially very expensive brute-force approach:
// untested
var names = context.Members.Select(m => m.Name).ToList();
names = names.Where(n => words.Any(w => n.Contains(w));

var a = new List<string>();
var b = new List<string>();
var c = a.Where(b.Contains);

Related

Multiple like in lambda expression

I have a string[] variable which i want to use in the lambda expression to filter data using like clause. I tried using contains, but it works like the 'in' clause, which is not what I need.
Please see the code below which behaves like in clause:
var inventories = ..............AsQuerable();
string[] strArray = <<somevalues>>;
inventories = inventories.Where(c => !strArray.Contains(c.columnName));
Could someone provide me the lambda expression which could filter records using like instead of in using an array.
The only methods LINQ provide for this purpose is .Where(), .StartsWith() or .EndsWith().. Also, there is pretty similar question here How to do SQL Like % in Linq?
Unlike VB.NET, C# has no builtin like-operator. However, you can use the operator from VB.NET easily. What you have to do is to reference the assembly Microsoft.VisualBasic.dll and include a using Microsoft.VisualBasic.CompilerServices; at the top of your file. Then you can do
var inventories = ..............AsQuerable();
string[] strArray = <<somevalues>>;
inventories = inventories.Where(c => !strArray.Any(s => LikeOperator.LikeString(c.columnName, s, CompareMethod.Text)));
I'm not entirely sure what you are trying to do, but I think this is what you are trying to accomplish. If not, please provide some more information and I will update my answer.
To check if a string is equal to a part of another string (which like does), you can use the .Contains method:
bool contains = "Some fancy sentence".Contains("fancy");
This will evaluate to true. Given your example, this would result in the following:
var inventories = ..............AsQuerable();
string[] strArray = <<somevalues>>;
inventories = inventories.Where(inv => !strArray.Any(s => inv.columnName.Contains(s)));
This checks all inventories and removes all inventories where the inventory column name (partially) occurs in any of the strArray values.
It is not pure Lambda expression, but Maybe it can help:
List<SomeObject> inventories = new List<SomeObject>();
// add objects to list...
string[] strArray = <<somevalues>>;
// result will be stored here
List<SomeObject> filtered = new List<SomeObject>();
foreach (var itm in strArray)
{
// LIKE '%SOMEVALUE%'
var match = inventories.Where(x => x.columnName.Contains(itm)).ToList();
// LIKE '%SOMEVALUE'
// var match = inventories.Where(x => x.columnName.StartsWith(itm)).ToList();
// LIKE 'SOMEVALUE%'
// var match = inventories.Where(x => x.columnName.EndsWith(itm)).ToList();
foreach (var m in match)
filtered.Add(m);
}

Using a dictionary as a source of Regex.Replace patterns in a Linq statement

In C#, I know how to use Regex.Replace a Linq query to replace substrings within an input string, as shown in this code sample.
var standards = _db.MapsFromOws.AsEnumerable().Select(m =>
m.Section).Distinct().AsEnumerable();
var enumerable = standards as IList<string> ?? standards.ToList();
const string elaPattern1 = #"LA.\d{1,2}-\d{1,2}.(\d{1,2}).([A-z]{1,2}).(\d{1,2})";
const string elaReplace1 = "$1.$2.$3";
var ela1 = enumerable
.AsEnumerable()
.Select(
m =>
new TranslationSelectModel
{
Section = m,
/* If m is a match to elaPattern1 then replace else m*/
Translation = Regex.Replace(m, elaPattern1, elaReplace1)
})
.OrderBy(m => m.Section).AsEnumerable();
This works well if there is only one pattern I need to replace, but what if I have to apply a set of pattern-replacements in the same list?
I had an idea of using a Dictionary<string,string> as a source of Regex patterns and replacement string. For example,
var regexPatternDictionary = new Dictionary<string, string>()
{
{#"LA.\d{1,2}-\d{1,2}.(\d{1,2}).([A-z]{1,2}).(\d{1,2})","$1.$2.$3"},
{#"MA.9-12.HS.([A-z])-([A-z]{0,3}).([A-z]).(\d)(.[A-z])*","HS.$1-$2.$3.$4$5"}
};
My question is how I would be able to use Regex.Replace() so that it matches each item in the enumerable to the regular expression dictionary instead of a single string variable?
The algorithm I'm seeing in my mind is:
For each item in enumerable
If item is a match to a dictionary, then apply replacement
Loop to next item
Not sure if I understand your problem 100%, but try something like this:
var result = enumerable.Select(x => replaceDictionary
.Aggregate(x, (y,z) => Regex.Replace(y, z.Key, z.Value))
.ToArray()

Intersect Two Lists c#

Hello I have these two Lists
List<string> list1 = {"404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg|Name1", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg|Name2", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29210_868.jpg|Name3"}
List<string> list2 = {"404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg","404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg"}
I want to intersect the values of list1 separating by '|' character, with the list2 values, but I want to return the full string of list1 and not only the first part separated by '|' character.
This is the result i want:
var finalList = {"404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg|Name1", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg|Name2"}
I dont know if its possible with the instersect function or there is another approach I can use. I've tried using Contains function in a predicate but it takes to much time to find the matches.
I'm using large lists with 2000 elements approx.
Thanks!
Try this, gives the expected results in LinqPad, using your example:
var intersection =
list1.Join(
list2,
l1 => l1.Split('|')[0], //Selector for items from the inner list splits on '|'
l2 => l2, //Select the current item
(l1, l2) => l1);
Compile list2 into a HashSet<string> to allow fast lookups. Then, use a simple Where filter to perform lookups of substrings from list1 against this set.
List<string> list1 = new List<string> { "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg|Name1", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg|Name2", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29210_868.jpg|Name3" };
List<string> list2 = new List<string> { "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg" };
var list2HashSet = new HashSet<string>(list2);
var finalList = list1.Where(s => list2HashSet.Contains(s.Substring(0, s.IndexOf('|')))).ToList();
Note that s.Substring(0, s.IndexOf('|')) is semantically equivalent to s.Split('|')[0] (assuming that all your strings contain |), but avoids the overhead of allocating another string instance for the text behind the |.
Use where to iterate over the list. Use the Split method to get the first part you are interested in, and then check to see if list2 contains that string. Finally call ToList to convert the result to a list.
var finalList = list1.Where(x => list2.Contains(x.Split(new []{'|'})[0})).ToList();

Check array for duplicates, return only items which appear more than once

I have an text document of emails such as
Google12#gmail.com,
MyUSERNAME#me.com,
ME#you.com,
ratonabat#co.co,
iamcool#asd.com,
ratonabat#co.co,
I need to check said document for duplicates and create a unique array from that (so if "ratonabat#co.co" appears 500 times in the new array he'll only appear once.)
Edit:
For an example:
username1#hotmail.com
username2#hotmail.com
username1#hotmail.com
username1#hotmail.com
username1#hotmail.com
username1#hotmail.com
This is my "data" (either in an array or text document, I can handle that)
I want to be able to see if there's a duplicate in that, and move the duplicate ONCE to another array. So the output would be
username1#hotmail.com
You can simply use Linq's Distinct extension method:
var input = new string[] { ... };
var output = input.Distinct().ToArray();
You may also want to consider refactoring your code to use a HashSet<string> instead of a simple array, as it will gracefully handle duplicates.
To get an array containing only those records which are duplicates, it's a little moe complex, but you can still do it with a little Linq:
var output = input.GroupBy(x => x)
.Where(g => g.Skip(1).Any())
.Select(g => g.Key)
.ToArray();
Explanation:
.GroupBy group identical strings together
.Where filter the groups by the following criteria
.Skip(1).Any() return true if there are 2 or more items in the group. This is equivalent to .Count() > 1, but it's slightly more efficient because it stops counting after it finds a second item.
.Select return a set consisting only of a single string (rather than the group)
.ToArray convert the result set to an array.
Here's another solution using a custom extension method:
public static class MyExtensions
{
public static IEnumerable<T> Duplicates<T>(this IEnumerable<T> input)
{
var a = new HashSet<T>();
var b = new HashSet<T>();
foreach(var x in input)
{
if (!a.Add(x) && b.Add(x))
yield return x;
}
}
}
And then you can call this method like this:
var output = input.Duplicates().ToArray();
I haven't benchmarked this, but it should be more efficient than the previous method.
You can use the built in in .Distinct() method, by default the comparisons are case sensitive, if you want to make it case insenstive use the overload that takes a comparer in and use a case insensitive string comparer.
List<string> emailAddresses = GetListOfEmailAddresses();
string[] uniqueEmailAddresses = emailAddresses.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
EDIT: Now I see after you made your clarification you only want to list the duplicates.
string[] duplicateAddresses = emailAddresses.GroupBy(address => address,
(key, rows) => new {Key = key, Count = rows.Count()},
StringComparer.OrdinalIgnoreCase)
.Where(row => row.Count > 1)
.Select(row => row.Key)
.ToArray();
To select emails which occur more then once..
var dupEmails=from emails in File.ReadAllText(path).Split(',').GroupBy(x=>x)
where emails.Count()>1
select emails.Key;

FindAll search question

I have a list like this:
item.Add("a");
item.Add("as");
item.Add("b");
item.Add("fgs");
item.Add("adsd");
How can I find all items that start with (for example) "a"?
This "a" is not some hardcoded string, so I will need a function that do this for each string.
I try with FindAll, but I did not figured out how it works.
Br, Wolfy
If by "start with" you mean the first char, then:
item.FindAll(i => i[0] == 'a');
if you mean a string (may be other than 1 char) then:
item.FindAll(i => i.StartsWith("a"));
If you want a different comparison, such as case-insensitive, locale-based, etc. then do the relevant IndexOf such as:
item.FindAll(i => i.IndexOf("a", StringComparison.CurrentCultureIgnoreCase) == 0);
All of the above can be easily adapted to be use a relevant char or string variable or parameter.
If you don't need the extra properties and methods provided by a list, then it will be more efficient to use Where than FindAll as FindAll creates a new list, and does so in all at once, while Where will enumerate the matching results as it is iterated through.
Or with LINQ
from i in items where i.StartsWith("a") select i;
for NET2.0 you may use this method:
'pattern' is an argument to look for (f.e. "a")
private List<string> FindAll(List<string> list, string pattern)
{ // returns found results
return list.FindAll(delegate(string item)
{
return item.StartsWith(pattern);
});
}
I thought you have another list that contains the startswith criteria strings. Lets call your items "words" and the other list "keywords". So the below query will return what you want.
List<string> words = new List<string>();
words.Add("a");
words.Add("as");
words.Add("b");
words.Add("fgs");
words.Add("adsd");
List<string> keywords = new List<string>();
keywords.Add("a");
keywords.Add("b");
var result = words.FindAll(o =>
keywords.Any(a => o.StartsWith(a))
);
This result has the words that starts with any of the keyword from keywords.
List<string> item = new List<string>();
item.Add("a");
item.Add("as");
item.Add("b");
item.Add("fgs");
item.Add("adsd");
var res1 = item.FindAll(i => i.StartsWith("a"));
var res2 = item.Where(i => i.StartsWith("a"));
Try this
item.FindAll(i => i.Contains("a"));
This will return a List containting only the filtered strings.

Categories