How to do "nothing" in the else part of ternary operator - c#

I want to filter values of a list based on whether or not they are contained in some other list. If an element is in the list I will select it, else I want to skip it or basically do nothing.
Below is what I tried to do. How can I achieve this?
List<string> sheetNames = new List<string>() {"1","10"};
List<string> projects= new List<string>() {"1","2","3","4","5","6","7"};
IEnumerable<string> result =
sheetNames.Select(x => projects.Contains(x)
? x
: /*Want to do nothing here */);

You can use Enumerable.Intersect method to get the common values from the two lists.
IEnumerable<string> commonValues = projects.Intersect(sheetNames);

List<string> sheetNames = new List<string>() {"1","10"};
List<string> projects= new List<string>() {"1","2","3","4","5","6","7"};
IEnumerable<string> result = sheetNames.Where(x => projects.Contains(x));

Related

C#: How do i get 2 lists into one 2-tuple list in

I have 2 Lists. First one is Type string. The second is type object. Now I want to get both lists into a Tuple<string,object>.
like this
var List = new(string list1, object list2)[]
How do I do this?
I had to create 2 seperate lists, because I am Serializing the object and the serializing wouldn't work if i had a List<Tuple<string,object>> in the first place.
Both lists can get big so maybe with foreach loop?
You can use the Zip method to create one list of the two:
var lst = new List<string>() { "a", "b" };
var obj = new List<object>() { 1, 2 };
var result = lst.Zip(obj, (x, y) => new Tuple<string, object>(x, y))
.ToList();
You can use the Linq Zip method:
List<string> list1 = GetStrings();
List<object> list2 = GetObjects();
var merged = list1.Zip(list2, (a, b) => Tuple.Create(a, b));

Contains without order

I want to search a list of strings using a set of characters and want to find matches regardless of order. For example if my list contains
List<string> testList = new List<string>() { "can", "rock", "bird" };
I want to be able to search using "irb" and have it return bird. I have to do this many times so I am looking for the most efficient way of doing it.
var query = "irb";
List<string> testList = new List<string>() { "can", "rock", "bird" };
var result = testList.Where(i => query.All(q => i.Contains(q)));
For each item in the testList test to see if it contains all the letters in query
For your scenario, you need to check each character of word in another list of word.
For that, you can do like this :
// Checks whether all character in word is present in another word
Func<string, string, bool> isContain = (s1, s2) =>
{
int matchingLength = 0;
foreach (var c2 in s2.ToCharArray())
{
foreach (var c1 in s1.ToCharArray())
{
if (c1 == c2)
++matchingLength;
}
}
// if matched length is equal to word length given, it would be assumed as matched
return s2.Length == matchingLength;
};
List<string> testList = new List<string>() { "can", "rock", "bird" };
string name = "irb";
var fileredList = testList.Where(x => isContain(x, name));
If you don't care about matching duplicates than checking if all characters in a sequence you are searching for are contained in the word would do for predicate:
"irb".Except("bird").Count() == 0
And whole condition:
List<string> testList = new List<string>() { "can", "rock", "bird" };
var search = "irb";
var matches = testList.Where(word => !search.Except(word).Any());
Notes:
you need to normalize all words to lowercase if you need mixed case letters to match.
if performance of searching for different values is critical - convert search string to HashSet first and do except manually.
if you need to match different values against same list many times - convert list of strings to list of HashSet and use search.All(c => wordAsHashSet.Contains(c)) as condition.
You can use linq to achieve this
List<string> testList = new List<string>() { "can", "rock", "bird" };
var lst = testList.Where(x => x.ToUpperInvariant().Contains("IRD")).ToList();
Make sure you also compare the cases using ToUpper and the string you want to compare also make it UpperCase

Intersect 2 list if first list contains part of another

I have 2 list of string, list A and list B. list A is a list of strings containing paths, and the other contains strings of folder. Examples:
List<string> listA = new List<string>{ "c:\myPath\FolderA\blabla\", "c:\myPath\FolderB\blabla2\", "c:\myPath\FolderA\blabla3\" "c:\myPath\FolderC\blabla\"};
List<string> listB = new List<string> { "FolderA, FolderC"};
I want to have a method that compares the 2 list. If listA contains any of listB it is valid, else I don't want it. So based on this logic I'd have:
List<string> listReturn = new List<string>{ "c:\myPath\FolderA\blabla\", "c:\myPath\FolderA\blabla3\" "c:\myPath\FolderC\blabla\"};
So far all I've done is a method that iterates through the first list and does a Contain call on the string with a Linq Any call, like this:
private static List<string> FilterList(List<string> listA, List<string> listB)
{
List<string> listReturn = new List<string>();
foreach (string val in listA)
{
if (listB.Any(item => val.Contains(item)))
{
listReturn.Add(val);
}
}
return listReturn;
}
It's not bad, but I want to use a Linq approach or a .NET approach if there's an Intersect method available for this. Thank you.
Use Where() against the listA to filter items in this list and Exists() on listB for the filter condition:
List<string> listA = new List<string> {#"c:\myPath\FolderA\blabla\", #"c:\myPath\FolderA\blabla2\", #"c:\myPath\Folder\blabla3\", #"c:\myPath\FolderC\blabla\"};
List<string> listB = new List<string> { "FolderA", "FolderC" };
var intersect = listA.Where(a => listB.Exists(b => a.Contains(b)));
Try this
var result = listA.Where(i => listB.Any(y => i.Contains(y)).ToList();

Compare value to array of strings using StartsWith

I have an array:
string[] exceptions = new string[] { "one", two", "one_1", "three" };
.. I want to be able to say:
var result = from c in myCollection
where not c.Property[3].Value.StartWith(exceptions)
select c;
So I want myCollection to be filtered to only show those records whose Property[3].Value does not StartWith a value in the exceptions array. I know StartsWith doesn't take a collection so I'm unsure if this is possible via LINQ or not.
Is this possible in LINQ?! Or am I trying to shoehorn my problem into a LINQ solution?
EDIT: I should say, Contains is not an option since I only want to exclude elements whose property startswith the exception string.
var result = myCollection.Where(c =>
exceptions.All(e =>
!c.Property[3].Value.StartsWith(e));
Try this:
string[] exceptions = new string[] { "one", "two", "one_1", "three" };
var result = from c in myCollection
where !exceptions.Any(exception =>
c.Property[3].Value.StartsWith(exception))
select c;
You could use IndexOfAny (and check result is index position zero) as that takes a collection.
You can select the collection of item you don't want then do a IEnumerable.Except().
I should look like this :
var result = from c in myCollection
where not c.Property[3].Value.StartWith(exceptions)
select c;
var finalResult = myCollection.Except(myCollection.Select(i => i.StartWith(exception)));
var result = myCollection
.where(
rs=>exceptions
.where(
rs1=>!rs.property[3].value.startsWith(rs1)
)
)

Using lambda expressions to get a subset where array elements are equal

I have an interesting problem, and I can't seem to figure out the lambda expression to make this work.
I have the following code:
List<string[]> list = GetSomeData(); // Returns large number of string[]'s
List<string[]> list2 = GetSomeData2(); // similar data, but smaller subset
List<string[]> newList = list.FindAll(predicate(string[] line){
return (???);
});
I want to return only those records in list in which element 0 of each string[] is equal to one of the element 0's in list2.
list contains data like this:
"000", "Data", "more data", "etc..."
list2 contains data like this:
"000", "different data", "even more different data"
Fundamentally, i could write this code like this:
List<string[]> newList = new List<string[]>();
foreach(var e in list)
{
foreach(var e2 in list2)
{
if (e[0] == e2[0])
newList.Add(e);
}
}
return newList;
But, i'm trying to use generics and lambda's more, so i'm looking for a nice clean solution. This one is frustrating me though.. maybe a Find inside of a Find?
EDIT:
Marc's answer below lead me to experiment with a varation that looks like this:
var z = list.Where(x => list2.Select(y => y[0]).Contains(x[0])).ToList();
I'm not sure how efficent this is, but it works and is sufficiently succinct. Anyone else have any suggestions?
You could join? I'd use two steps myself, though:
var keys = new HashSet<string>(list2.Select(x => x[0]));
var data = list.Where(x => keys.Contains(x[0]));
If you only have .NET 2.0, then either install LINQBridge and use the above (or similar with a Dictionary<> if LINQBridge doesn't include HashSet<>), or perhaps use nested Find:
var data = list.FindAll(arr => list2.Find(arr2 => arr2[0] == arr[0]) != null);
note though that the Find approach is O(n*m), where-as the HashSet<> approach is O(n+m)...
You could use the Intersect extension method in System.Linq, but you would need to provide an IEqualityComparer to do the work.
static void Main(string[] args)
{
List<string[]> data1 = new List<string[]>();
List<string[]> data2 = new List<string[]>();
var result = data1.Intersect(data2, new Comparer());
}
class Comparer : IEqualityComparer<string[]>
{
#region IEqualityComparer<string[]> Members
bool IEqualityComparer<string[]>.Equals(string[] x, string[] y)
{
return x[0] == y[0];
}
int IEqualityComparer<string[]>.GetHashCode(string[] obj)
{
return obj.GetHashCode();
}
#endregion
}
Intersect may work for you.
Intersect finds all the items that are in both lists.
Ok re-read the question. Intersect doesn't take the order into account.
I have written a slightly more complex linq expression that will return a list of items that are in the same position (index) with the same value.
List<String> list1 = new List<String>() {"000","33", "22", "11", "111"};
List<String> list2 = new List<String>() {"000", "22", "33", "11"};
List<String> subList = list1.Select ((value, index) => new { Value = value, Index = index})
.Where(w => list2.Skip(w.Index).FirstOrDefault() == w.Value )
.Select (s => s.Value).ToList();
Result: {"000", "11"}
Explanation of the query:
Select a set of values and position of that value.
Filter that set where the item in the same position in the second list has the same value.
Select just the value (not the index as well).
Note I used:
list2.Skip(w.Index).FirstOrDefault()
//instead of
list2[w.Index]
So that it will handle lists of different lengths.
If you know the lists will be the same length or list1 will always be shorter then list2[w.Index] would probably a bit faster.

Categories