Reputation: 153
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;
}
Upvotes: 0
Views: 83
Reputation: 216302
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);
Upvotes: 3
Reputation: 18463
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);
}
Upvotes: 1
Reputation: 919
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);
Upvotes: 0
Reputation: 156
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;
}
Upvotes: 1