Recht88
Recht88

Reputation: 153

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;
    }

Upvotes: 0

Views: 83

Answers (4)

Steve
Steve

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

Moha Dehghan
Moha Dehghan

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

Valeh Mikayilzadeh
Valeh Mikayilzadeh

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

Raj Sappidi
Raj Sappidi

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

Related Questions