Check if List<string> exists - c#

This is my code
List<string> list = new List<string>() { "bfd", "jy", "aaaaa", "ndnk", "ntfn", "gfm", "gfm", "mhgd5h", "srsr", "ntr", "mtmyt", "dmy", "mmy6", "ngn9d", "y6m1", "d8dm", "bbbbb", "tym", "dmj", "trsh", "tsr"};
List<string> test = new List<string>() {"aaaaa","bbbbb","ccccc","ddddd","eeeee","fffff","ggggg" };
foreach (var a in list)
{
foreach (var i in test)
{
if (i.StartsWith(a) == false)
{
Console.WriteLine(i);
}
}
}
I want to output from the list and match in the test. If the test exists, then it will not be displayed. If there is no side output,But there may be a problem with my code, it will output the same value many times
The list contains aaaaa, according to logic, aaaaa should not be output

Try this:
List<string> list = new List<string>(){"bfd", "jy", "aaaaa", "ndnk", "ntfn", "gfm", "gfm", "mhgd5h", "srsr", "ntr", "mtmyt", "dmy", "mmy6", "ngn9d", "y6m1", "d8dm", "bbbbb", "tym", "dmj", "trsh", "tsr"};
List<string> test = new List<string>(){"aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee", "fffff", "ggggg"};
foreach (var a in list)
{
if (!test.Contains(a))
{
Console.WriteLine(a);
}
}

There are simple solutions using LINQ. But since I assume this is an exercise, I will show you the detailed version using loops.
The problem is that the WriteLine is inside the inner loop. Therefore you will get many repetitions. Store the outcome of the test in a Boolean variable and place the display part after the inner loop.
foreach (var a in list)
{
bool found = false;
foreach (var i in test)
{
if (i.StartsWith(a))
{
found = true;
break; // Exit the inner loop
}
}
if (!found)
{
Console.WriteLine(a); // We must output a here since i out of scope.
}
}
Also, if you want to know whether a specific string is contained in the list, you should probably replace i.StartsWith(a) with i == a.
The code becomes easier to read, if you extract the list search into its own method
private bool IsInList(List<string> list, string item)
{
foreach (string s in list)
{
if (s == item)
{
return true;
}
}
return false;
}
Now, you don't need the Boolean variable any more
foreach (var a in list)
{
if (!IsInList(test, a))
{
Console.WriteLine(a);
}
}
I used !condition (pronounce: "not condition") instead of condition == false. It's terser.
I assume that this is an exercise. In production code you would simply use the built in method Contains of the list.
foreach (var a in list)
{
if (!test.Contains(a))
{
Console.WriteLine(a);
}
}
or even (as #mjwills suggests in his comment):
foreach (var a in list.Except(test)) {
Console.WriteLine(a);
}

Related

How to compare the contents of two arrays and returning the index of the duplicated file?

I've made a method that compares the files within two file directories and it returns if there are files that are duplicated in the form of a bool. However, would actually want it to return the files name or the index of the file in its array so I can then delete the file so their are no complications when moving files into one directory. I've tried to cast the "==" compare statement to a string hoping it would give the files name but I forgot since its a boolean operation it will only return true or false.
static public string ModFileDupilcate(string[] SimsModDownloadDirectory, string[] SimsModsDirectory)
{
string NoDuplicateMods = "There are no duplicate mods";
foreach (var ModInDownloadDirectory in SimsModDownloadDirectory)
{
foreach (var ModInModsDirectory in SimsModsDirectory)
{
if (ModInDownloadDirectory == ModInModsDirectory)
{
string DuplicateMod = (ModInDownloadDirectory == ModInModsDirectory).ToString();
return DuplicateMod;
}
else
{
return NoDuplicateMods;
}
}
}
return NoDuplicateMods;
}
You can get the indexes of the matching strings with something like this
var result = SimsModDownloadDirectory.Select((x, i) =>
{return (SimsModsDirectory.Contains(x) ? i :-1);})
.Where(x => x != -1);
foreach(int index in result)
Console.WriteLine(index);
The idea is the following:
Enumerate with Select all the strings (x) in the first list with the overload that gives us also the index of the enumerated string (i), if the enumerated string is contained in the second list return its index otherwise return -1. Finally take with Where only the not -1 values extracted by the Select
Of course returning only the names of the duplicates is a lot more simple
var result = SimsModDownloadDirectory.Intersect(SimsModsDirectory);
foreach(string name in result)
Console.WriteLine(name);
These approaches are based on the exact match in case between the two strings to compare. So a string "Steve" will not match a string "steve".
If your requirements are to ignore case in the comparison then you could change to
var result = SimsModDownloadDirectory.Select((x, i) =>
{
return (SimsModsDirectory.Contains(x,
StringComparer.CurrentCultureIgnoreCase) ? i :-1);
}).Where(x => x != -1);
or to
var result = SimsModDownloadDirectory.Intersect(SimsModsDirectory,
StringComparer.CurrentCultureIgnoreCase);
The else in your code is the issue.
Sample code (untested)
static public string ModFileDupilcate(string[] SimsModDownloadDirectory, string[] SimsModsDirectory)
{
string NoDuplicateMods = "There are no duplicate mods";
foreach (var ModInDownloadDirectory in SimsModDownloadDirectory)
{
foreach (var ModInModsDirectory in SimsModsDirectory)
{
if (ModInDownloadDirectory == ModInModsDirectory)
{
return ModInModsDirectory;
}
}
}
return NoDuplicateMods;
}
The above only returns the first duplicate. For all duplicates, you have to maintain a list and return that at the end
static public List<string> ModFileDupilcate(string[] SimsModDownloadDirectory, string[] SimsModsDirectory)
{
var duplicateDirs = new List<string>();
foreach (var ModInDownloadDirectory in SimsModDownloadDirectory)
{
foreach (var ModInModsDirectory in SimsModsDirectory)
{
if (ModInDownloadDirectory == ModInModsDirectory)
{
duplicateDirs.Add(ModInModsDirectory);
}
}
}
return duplicateDirs;
}
I don't exactly know what are you trying to achieve. Your code does not tell us what should the return value be. If you want to tell the caller that "There is/isn't duplicate file names", you can easily return bool. If you want to return the "duplicate file names", you should return string[] or FileInfo[] or IReadOnlyCollection<string> or something similar. The advantage of returning a collection or array, is that the caller can easily see that if there is/isn't any duplicates, by checking the Length/Count of the returned value.
Using nested for loops, has a poor performance of O(n*m). Using a HashSet or LINQ's Intersect method, you can easily achieve the goal in O(n+m):
public static IReadOnlyList<string> FindDuplicateModFiles(string[] SimsModDownloadDirectory, string[] SimsModsDirectory)
{
var set = new HashSet<string>(SimsModDownloadDirectory);
var result = new List<string>();
foreach (string file in SimsModsDirectory)
{
if (set.Contains(file))
result.Add(file);
}
return result.AsReadOnly();
}
Or using LINQ:
public static IEnumerable<string> FindDuplicateModFiles2(string[] SimsModDownloadDirectory, string[] SimsModsDirectory)
{
return SimsModDownloadDirectory.Intersect(SimsModsDirectory);
}
If you want to remove the duplicates from the first collection, the best options is the LINQ's Except method:
public static IEnumerable<string> GetNonDuplicatesInFirst(string[] SimsModDownloadDirectory, string[] SimsModsDirectory)
{
return SimsModDownloadDirectory.Except(SimsModsDirectory);
}
static public IEnumerable<string> ModFileDupilcate(string[] SimsModDownloadDirectory,
string[] SimsModsDirectory)
{
var result = SimsModDownloadDirectory.Select((x, i) =>
SimsModsDirectory.Contains(x) ? x : string.Empty).
Where(x => !string.IsNullOrEmpty(x));
return result;
}
Call method like :
var resultOfDublicateFiles = ModFileDupilcate(SimsModDownloadDirectory,SimsModsDirectory);
Or
public static bool ModFileDupilcate(string[] SimsModDownloadDirectory,
List<string> SimsModsDirectory,out List<string> dublicatedFiles)
{
dublicatedFiles = new List<string>();
foreach (var ModInDownloadDirectory in SimsModDownloadDirectory)
{
foreach (var ModInModsDirectory in SimsModsDirectory)
{
if (ModInDownloadDirectory == ModInModsDirectory)
{
dublicatedFiles.Add(ModInModsDirectory);
}
}
}
return dublicatedFiles.Count > 0;
}
Call method like :
List<string> dublicatedFiles;
bool hasDublicatedFiles= ModFileDupilcate(new string["a","b","c"],new string["b","c","d","f"],out dublicatedFiles);

compare List<string> and List<T>

I'm using C# and framework 4.0.
I have a list of type string and another list of type class T;
How can I compare List with a List and save the difference?
private void simpleButton_Compare_Click(object sender, EventArgs e)
{
try
{
bool Is_Egal = true;
int i = 0;
foreach (string Od_Scan in Ordre_Scan)
{
if (!Outils.Get_Ordre_Donne()[i].NoOrdre.Contains(Od_Scan) && !String.IsNullOrWhiteSpace(Od_Scan))
{
Is_Egal = false;
Temp_Od_Scan.Add(Od_Scan);
}
i++;
}
foreach (Pers_Compare Od_Done in Outils.Get_Ordre_Donne())
{
if (!Ordre_Scan.Contains(Od_Done.NoOrdre) && !String.IsNullOrWhiteSpace(Od_Done.NoOrdre))
{
Is_Egal = false;
Temp_Od_Donne.Add(Od_Done);
}
else
{
Temp_Od_Donne_Egal.Add(Od_Done);
}
}
if (Is_Egal)
{
MessageBox.Show("égalité");
}
else
{
MessageBox.Show("PAS égalité");
}
}
catch (Exception excThrown)
{
MessageBox.Show(excThrown.Message);
}
}
and the data :
List<string> Ordre_Scan= new List<string> { "azer","qsdf"};
Pers_Compare obj = new Pers_Compare();
obj.Nolv = 1;
obj.Noordre = "qsdf"
Pers_Compare obj2 = new Pers_Compare();
obj2.Nolv = 1;
obj2.Noordre = "wxcv"
List<Pers_Compare> Ordre_Donne = new List<Pers_Compare>();
Ordre_Donne.add(obj);
Ordre_Donne.add(obj2);
And I want to save the data in Ordre_Donne but not in Od_Scan and vice versa.
foreach (string Od_Scan in Temp_Od_Scan)
{
all item that not found in List A
--> wxcv
}
foreach (var Od_Done in Temp_Od_Donne)
{
all item that not found in List B
--> azer
}
The answer given for a slightly different question (comparing a List with another List) seems to me to be a good solution for your issue, they address multiple issues to do with comparisons of lists.
EDIT: However you should be more specific with your requirements i.e. what exactly is a 'difference', e.g. is {1,1,2} and {1,2} the same?
Here is the answer given the most votes... (included here just encase it gets removed for some reason (as per Bob' suggestion))
"
DESCRIPTION:
I need to check that they both have the same elements, regardless of their position within the list. Each MyType object may appear multiple times on a list. Is there a built-in function that checks this? What if I guarantee that each element appears only once in a list?
EDIT: Guys thanks for the answers but I forgot to add something, the number of occurrences of each element should be the same on both lists.
ANSWER:
If you want them to be really equal (i.e. the same items and the same number of each item), I think that the simplest solution is to sort before comparing:
Enumerable.SequenceEqual(list1.OrderBy(t => t), list2.OrderBy(t => t))
Edit:
Here is a solution that performs a bit better (about ten times faster), and only requires IEquatable, not IComparable:
public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2) {
var cnt = new Dictionary<T, int>();
foreach (T s in list1) {
if (cnt.ContainsKey(s)) {
cnt[s]++;
} else {
cnt.Add(s, 1);
}
}
foreach (T s in list2) {
if (cnt.ContainsKey(s)) {
cnt[s]--;
} else {
return false;
}
}
return cnt.Values.All(c => c == 0);
}
Edit 2:
To handle any data type as key (for example nullable types as Frank Tzanabetis pointed out), you can make a version that takes a comparer for the dictionary:
public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer) {
var cnt = new Dictionary<T, int>(comparer);
...
"
var list1 = Ordre_Donne.Where(o => !Ordre_Scan.Any(s => s == o.Noordre));
var list2 = Ordre_Scan.Where(s => !Ordre_Donne.Any(o => o.Noordre == s));
You can either implement IComparable on your Pers_Compare class, which will look something like:
public int CompareTo(string other)
{
return this.Noordre.CompareTo(other);
}
Or, if you don't have control of the data structure, you could do something like
var Temp_Od_Donne = from od in Ordre_Donne
where !Ordre_Scan.Contains(od.Noordre)
select od;
var Temp_Od_Scan = from os in Ordre_Scan
where !Ordre_Donne.Select(od => od.Noordre).Contains(os)
select os;

convert foreach loop to linq code

the below code is working as expected but I'm looking to convert the below code to use Linq?
any suggestions?
string[] selections = "Men,Women,Boys".Split(',');
int _chkboxId = 0;
int _chkboxTextId = 1;
try
{
string id = "lstchk_" + _chkboxId;
while (!driver.FindElement(By.Id(id)).Equals(null))
{
string checkboxId = String.Format("lstchk{0}", _chkboxTextId);
string checkboxName = driver.FindElement(By.Id(checkboxId)).Text;
foreach (string match in selections)
{
if (checkboxName == match.Trim())
{
//matched... do more work here...
}
}
}
foreach (string match in selections.Where(match => checkboxName == match.Trim()))
{
//matched... do more work here...
}
If your selections list contains only distinct values, than you could use
if(selections.Any(match=>match.Trim().Equals(checkboxName)))
{
//Do work
}
instead of your loop. Same if your list may contain non-distinct values, but the work should be done only once for each checkboxName
switch(checkboxName) {
case "Men":
case "Women":
case "Boys":
// do more work here
default:
// no match, bail
}
Sometimes, there's just a different way to write the code.
How would you convert this simple foreach to a linq statement?
public List<string> GetItems()
{
var items = new List<string>();
foreach (Ranorex.ListItem item in ranorexComboBox.Items)
{
items.Add(item.Text);
}
return items;
}

How to skip a specific position within a for each loop in c sharp?

List<string> liste = new List<String>
{
"A","B","C","D"
};
foreach (var item in liste)
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
for (int i = 0; i < liste.Count; i++)
{
if (i == 0)
continue;
System.Diagnostics.Debug.WriteLine(liste[i].ToString());
}
How do i skip a specific position in a foreach loop? I do not want to evaluate any values, but just skip the position x.
It has to be a specific position. One could choose position 0 or maybe position 7.
It is very easy to skip the first item in the list:
foreach(var item in list.Skip(1))
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
If you want to skip any other element at index n, you could write this:
foreach(var item in list.Where((a,b) => b != n))
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
In this example I use a lambda expression that takes two arguments: a and b. Argument a is the item itself, while argument b is the index of the item.
The relevant pages on MSDN that describe these extension methods are:
IEnumerable.Skip()
IEnumerable.Where()
You could even write your own extension method that allows you to skip an element in a list:
public static class MyEnumerableExtensions
{
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> list, int index)
{
var i = 0;
foreach(var item in list)
{
if(i != index)
yield return item;
i++;
}
}
}
This will allow you to write something like this to skip an item:
foreach(var item in list.SkipAt(2))
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
A foreach loop iterates over a collection that implements IEnumerable. The enumerator exposes the current item and a method to move onto the next item - it has no concept of an index.
You could always do:
var i = 0;
foreach (var item in liste) {
if (i++ == skip) continue;
Debug.WriteLine(item.ToString());
}
But this seems unnecessarily contrived. If you need an index, go with a for loop.
The other option is to remove the undesired item from the List before iterating:
foreach (var item in liste.Take(n-1).Union(liste.Skip(n))) {
Debug.WriteLine(item.ToString());
}
I love list's .ForEach, here's my take using #Elian's .SkipAt(n) and .ForEach:
var list = new List<String> { "A", "B", "C", "D" };
list = list.SkipAt(1).ToList();
list.ForEach(Debug.WriteLine);
You should try using the enhanced version of the Where extension method that allows you to filter on item and index.
Check the reference.
http://msdn.microsoft.com/en-us/library/bb549418.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Verbatim list");
List<string> list = new List<String> { "A","B","C","D" };
foreach (var item in list)
{
Console.WriteLine(item.ToString());
}
Console.WriteLine("Filtered list");
int itemToSkip = 2;
foreach (var item in list.Where((item, index) => index != itemToSkip))
{
Console.WriteLine(item.ToString());
}
Console.ReadKey();
}
}
}
This will give you the following output.
Verbatim list
A
B
C
D
Filtered list
A
B
D
To skip a position inside the foreach loop, one option is that you can skip the action inside the foreach loop by using an if statement, like
foreach(var item in liste)
{
if (item != 'X')
{
//do something
}
}
But i am waiting for better solutions

Check if collection is empty or not

public ActionResult Create(FormCollection collection, FormCollection formValue)
{
try
{
Project project = new Project();
TryUpdateModel(project, _updateableFields);
var devices = collection["devices"];
string[] arr1 = ((string)devices).Split(',');
int[] arr2 = Array.ConvertAll(arr1, s => int.Parse(s));
project.User = SessionVariables.AuthenticatedUser;
var time = formValue["Date"];
project.Date = time;
project.SaveAndFlush();
foreach (int i in arr2)
{
Device d = Device.Find(i);
d.Projects.Add(project);
d.SaveAndFlush();
}
return RedirectToAction("Index");
}
catch (Exception e)
{
return View(e);
}
}
I want to wrap the foreach in a if statement which checks if
var devices = collection["devices"];
is empty or not. If its empty the for each should not be executed. For the record, collection["devices"] is a collection of checkbox values from a form.
You can use the Count field to check if the collection is empty or not
so you will end up with something like this :
if(devices.Count > 0)
{
//foreach loop
}
You can use the method Any to know if a collection as any element.
if (devices.Any())
{
//devices is not empty
}
You do not need to check if the collection is empty, if it is empty the code inside the ForEach will not be executed, see my example below.
using System;
using System.Collections.Generic;
namespace Test
{
class Program
{
static void Main(string[] args)
{
List<string> emptyList = new List<string>();
foreach (string item in emptyList)
{
Console.WriteLine("This will not be printed");
}
List<string> list = new List<string>();
list.Add("item 1");
list.Add("item 2");
foreach (string item in list)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
}
Your code, as it stands, won't work, as you say that collection["devices"] is a collection of checkbox values, and yet you're casting it to a string. Do you mean collection is the checkbox values? What is the exact type of collection?
Any object that implements ICollection or ICollection<T> can be checked whether it's empty or not by checking if the Count property is greater than zero.
How about checking the array length
if (arr2.length > 0)
{
foreach (int i in arr2)
{
Device d = Device.Find(i);
d.Projects.Add(project);
d.SaveAndFlush();
}
}
This worked for me in Dot Net Core but only for IEnumerable of Models not Entities
(I got a bit of help from AutoMapper)
Cast it as a List then check the Capacity
IEnumerable<vwPOD_Master> podMasters = _podRepository.GetNewPods(PartNumber);
IEnumerable<NewPODsDTO> podList = Mapper.Map<IEnumerable<NewPODsDTO>>(podMasters);
if (((List<NewPODsDTO>)podList).Capacity == 0) {
return NotFound();
}

Categories