user1985189
user1985189

Reputation: 669

How to get values AND indices of duplicate items in a list?

I have a list of file names (targetFileList), some of which are duplicates (ex. I have two files called m4.txt). The following statement finds the duplicated filenames and adds them to another list (currentTargetFiles):

currentTargetFiles = targetFileList.FindAll(item => item == baselineFilename);

As is, this line is returning a list of strings (filenames), which is good, but I also need their index value. Is there some way to modify it so that it also returns the indices of the files?

Upvotes: 2

Views: 3229

Answers (4)

Jim Mischel
Jim Mischel

Reputation: 134035

You can select all the items, with their indexes, with:

tempList = targetFileList.Select((item, index) => 
    new { Value = item, Index = index }).Where(x => x.Value == baselineFilename);

Now, you can create lists of the names and corresponding indexes with:

var indexes = tempList.Select(x => x.Index).ToList();

And the values:

currentTargetFiles = tempList.Select(x => x.Value).ToList();

Then, indexes[0] will hold the list index of currentTargetFiles[0].

Upvotes: 2

user166390
user166390

Reputation:

Well, here is my answer to "find the duplicate names and their indices". It might not fit the presented problem exactly, as there is no baselineFilename considered - but that is covered by other answers. YMMV.

var names = new [] {"a", "a", "c", "b", "a", "b"};

var duplicatesWithIndices = names
    // Associate each name/value with an index
    .Select((Name, Index) => new { Name, Index })
    // Group according to name
    .GroupBy(x => x.Name)
    // Only care about Name -> {Index1, Index2, ..}
    .Select(xg => new {
        Name = xg.Key,
        Indices = xg.Select(x => x.Index)
    })
    // And groups with more than one index represent a duplicate key
    .Where(x => x.Indices.Count() > 1);

// Now, duplicatesWithIndices is typed like:
//   IEnumerable<{Name:string,Indices:IEnumerable<int>}>

// Let's say we print out the duplicates (the ToArray is for .NET 3.5):
foreach (var g in duplicatesWithIndices) {
    Console.WriteLine("Have duplicate " + g.Name + " with indices " +
        string.Join(",", g.Indices.ToArray()));
}

// The output for the above input is:
// > Have duplicate a with indices 0,1,4
// > Have duplicate b with indices 3,5

Of course, the provided results must be used correctly - and this depends on what must ultimately be done.

Upvotes: 7

talles
talles

Reputation: 15104

Is linq a requirement?

A traditional for loop and a dictionary would do fine:

Dictionary<int, string> currentTargetFiles = new Dictionary<int, string>();
for (int i = 0; i < targetFileList.Count; ++i)
    if(targetFileList[i] == baselineFilename)
        currentTargetFiles.Add(i, targetFileList[i]);

P.S.:

Just realized that you comparing an exact string (item == baselineFilename).

If this is the case you don't even need to keep each value for each index (since all values are the same).

List<int> currentTargetFilesIndices = new List<int>();
for (int i = 0; i < targetFileList.Count; ++i)
    if(targetFileList[i] == baselineFilename)
        currentTargetFiles.Add(i);

Upvotes: 1

Fede
Fede

Reputation: 44048

int i = -1;
var currentTargetFiles = targetFileList.Select(x => new
                                                        {
                                                           Value = x,
                                                           Index = i++
                                                        })
                                       .Where(x => x.Value == baselineFilename);

Upvotes: 2

Related Questions