Remove from List<T> based on sub-string match - c#

sampleList.RemoveAll(a=>a.reference.Contains("123"));
This line of code does not remove any item from the list whereas
sampleList.RemoveAll(a=>!a.reference.Contains("123"));
removes all the items.
I have currently resorted to making another list and going through a for loop and adding stuff to the second list, but I dont really like this approach.
Is there a cleaner way to achieve what I am trying ?

The fact that the second example "removes all the items" and the first removes none, leads me to conclude that none of the item's reference property in the list contains the string "123".
Elementry my dear watson ;)

I would guess your sampleList contains no elements containing "123". This is proven by the fact that the first attempt removes nothing, and the second attempt (which is the reverse of the first) removes everything.
Here is a sample console application I wrote to test out what I think your trying to achieve, and it works:
static void Main(string[] args)
{
List<string> sampleList = new List<string>(new string[]
{
"Some String", "Some Other String", "Hello World", "123456789", "987654123"
});
Console.WriteLine("Items:");
foreach (string item in sampleList)
{
Console.WriteLine(item);
}
Console.WriteLine("\nRemoving items containing \"123\"...");
int itemsRemoved = sampleList.RemoveAll(str => str.Contains("123"));
Console.WriteLine("Removed {0} items.", itemsRemoved);
Console.WriteLine("\nItems:");
foreach (string item in sampleList)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
Start by checking the values of the items in your collection. Once you've made sure the values contain what they should, check the return value of RemoveAll(...) to check the right number of elements have been removed.

Related

Print text of elements from an list in C#

I have to print all the text of the web elements, so i am storing the web elements in list "test" and then getting text of each web element and keep them adding to other list "Title".
Now when i am trying to print all the elements of list "Title".But only the text of 1st element is printed.
Please help me to find where i am going wrong.
public void PrintText()
{
var Title = new List<string>();
IList <IWebElement> test=Controls.GetWebElementList(X-path);
foreach (var g in test)
{
Title.Add(Controls.GetText(x-path));
}
foreach (var h in Title)
{
Console.WriteLine(h);
}
}
It's not that clear how Controls.GetWebElementList() is defined.
Ideally to extract the texts you have to induce WebDriverWait for VisibilityOfAllElementsLocatedBy() and you can use the following Locator Strategy:
IList <IWebElement> test = new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.XPath("X-path")));
Your code looks fine.
Try to verify the first list to print their values.
And then run again, maybe your first line had only one value.

If string in list occurs in string, then add to list

had a look around and found many similar questions but none matching mine exactly.
public bool checkInvalid()
{
invalidMessage = filterWords.Any(s => appmessage.Contains(s));
return invalidMessage;
}
If a string is found that matches a string in the list the boolean invalidMessage is set to true.
After this though I would like to be able to add each string found to a list. is there a way I can do this using .Contains() or can someone recommend me another way to go about this?
Many thanks.
Well, from your description, I thought here is what you want:
// Set of filtered words
string[] filterWords = {"AAA", "BBB", "EEE"};
// The app message
string appMessage = "AAA CCC BBB DDD";
// The list contains filtered words from the app message
List<string> result = new List<string>();
// Normally, here is what you do
// 1. With each word in the filtered words set
foreach (string word in filterWords)
{
// Check if it exists in the app message
if (appMessage.Contains(word))
{
// If it does, add to the list
result.Add(word);
}
}
But as you said, you want to use LINQ, so instead of doing a loop, you can do it like this:
// If you want to use LINQ, here is the way
result.AddRange(filterWords.Where(word => appMessage.Contains(word)));
If what you want is to gets the words in filterWords that are contained in appmessage you can use Where:
var words = filterWords.Where(s => appmessage.Contains(s)).ToList();

Find item in list by property and know the item name

I have struggled with figuring out how to find an item in a list by checking for a property and then isolating and naming this item. I need to do this to set a value that corresponds with that specific string. It wouldn't work if I just found that there is one, or several items in the list that match the property. My code is massive, but here's a snippet of it:
List<string> diag_right = new List<string>();
diag_right.Add(b3); //Add the string b3
diag_right.Add(b5); //Add the string b5
diag_right.Add(b7); //Add the string b7
if (diag_right.Exists(a => a.Equals("")))
{
//Find the item (string name, b3, b5, etc.) that was found as matching the blank property
}
Is it possible to do this? I know I can do this by checking to see if each string matches this property individually, but is there a faster way to do this?
Many ways this can be achieved, I prefer simple approach, loop collection using index and modify matching field
for(int index=0; index< diag_right.Count(); index++)
{
if(diag_right[index] == "b3")
{
// update
diag_right[index] = "b8";
}
}
Linq approach
This approach I just used Linq to fetch all indexes for a matching string.
var indexes = diag_right.Where(e=>e.Equals("searchstring")).Select((c,i) => i).ToList();
foreach(int index in indexes) // loop through each line.
{
diag_right[index] = "newvalue"; // set new value.
}
Working Demo

Why am I getting ArgumentOutOfRangeException in Lists?

I am using List of Lists in my project. When i run program i get ArgumentOutOfRangeException. But there is no range specified in list.
I declared list like this:
public static List<List<string>> list = new List<List<string>>();
Now i want to add my name in the first "list" which is in the List of lists.
list[0].Add("Hussam"); //Here i get ArgumentOutOfRange Exception.
What should I do now?
But there is no range specified in list
No, there's an index specified (as an argument), and that's what's out of range. Look at your code:
list[0].Add("Hussam");
That's trying to use the first list in list - but is list is empty, there is no first element. The range of valid arguments to the indexer is empty, basically.
So first you want:
list.Add(new List<string>());
Now list[0] will correctly refer to your empty List<string>, so you can add "Hussam" to it.
You want to add an item to the first item in an empty list... That isn't going to work. First, add the list inside the other list:
public static List<List<string>> list = new List<List<string>>();
List<string> innerList = new List<string>();
list.Add(innerList);
innerList.Add("Hussam");
Why are you creating a list of a list? Wouldn't List suffice? What is happening here is the inner list is not being initialized.
list.Add(new List<string>());
list[0].Add("Jimmy");
In this case ocurred an exception because you tried acess an index which not exists, then you must add an inner initial list, which could be done follows:
list.Add(new new List<string>());
Or, if you want add an first name directly:
list.Add(new new List<string>(){"Hussam"});
Ok so first, you have to understand that the "index" only comes after the value has been declared. Lists behave different. They are not like arrays. You get the index in which you want to store the item and when you do that, you use the code array[index] = value;.
But in a List, to give a value to a completely new item, you use the method Add(value).
So here's a reminder: Systems.Collections.Generic.List<> has nothing to do with array[ ]s
You cannot access list[0] as there is no item at index 0. The list is empty.
You need to add a new List like this:
list.Add(new List<string> { "Hussam" });
or, assign a list to index 0 and then add to it as per your posted code:
list.Add(new List<string>());
list[0].Add("Hussam");
If you don't always know if the list will be be empty or not you can use FirstOrDefault (a LINQ method) to check if there is any entry at index 0 and assign one if not, otherwise use the existing inner list:
var innerList = list.FirstOrDefault();
if (innerList == null)
{
innerList = new List<string>();
list.Add(innerList);
}
innerList.Add("Hussam");
The problem is, your nested list hasn't been initialized, with anything.
So, calling the first item of the nested list is correctly telling you there is nothing in it.
To verify:
int superlistCounter = 1;
int sublistCounter = 1;
foreach(var sublist in list)
{
Console.WriteLine("Now in List #" + superlistCounter);
foreach(var item in sublist)
{
Console.WriteLine("List item #" + sublistCounter + ": " + item)
}
}
The output will be:
Now in List #1
It sounds like you're expecting:
Now in List #1
List Item #1: Hussam
To fix this, simply initialize your list!
public static List<List<string>> list = new List<List<string>>();
// ...
List<string> subList1 = new List<string>();
list.Add(subList1);
subList1.Add("Hussam");

How to check for list in LINQ

I am trying to read a file and process using LINQ.
I have a exclude list where if i encounter certain words in the file, i should omit that line
my code is
string sCodeFile = #"C:\temp\allcode.lst";
List<string> sIgnoreList = new List<string>() { "foo.c", "foo1.c" };
var wordsPerLine = from line in File.ReadAllLines(sCodeFile)
let items = line.Split('\n')
where !line.Contains(sIgnoreList.ToString())
select line;
foreach (var item in wordsPerLine)
{
console.WriteLine(item);
}
My LST file looks like below
\voodoo\foo.c
\voodoo\voodoo.h
\voodoo\std.c
\voodoo\foo1.h
in the end i want only
\voodoo\voodoo.h
\voodoo\std.c
How can i process the ignored list in contains? with my above code i dont get the desired output for sure
can any one help?
regards,
Karthik
Revised my answer. The bug is that you're doing a ToString on the ignore list, which certainly will not work. You must check each item in the list, which can be done using something like this:
where !sIgnoreList.Any(ignore => line.Contains(ignore))
A curiosity: since the above lambda is just passing a value into a method that only take the value as a parameter, you can write this even more compact as a method group like this:
where !sIgnoreList.Any(line.Contains)
Try this.
string sCodeFile = #"C:\temp\allcode.lst";
List<string> sIgnoreList = new List<string>() { "foo.c", "foo1.c" };
var wordsPerLine = File.ReadAllLines(sCodeFile).Where(n =>
{
foreach (var ign in sIgnoreList)
{
if (n.IndexOf(ign) != -1)
return false;
}
return true;
});
It passes the current element (n) to a lambda function, which checks it against every element of the sIgnoreList. Returning false means the element is ignored, true means it's returned.
Change it to:
where !sIgnoreList.Contains(line)
You need to compare each single line and check that it doesn't exist in the ignore list.
That's why the Vladislav's answer did not work.
Here's the working solution:
var result = from line in File.ReadAllLines(codeFile)
where !ignoreList.Any(line.Contains)
select line;
The problem was you didn't want to check for the whole path and messed up words/lines part a bit.

Categories