2

I really appreciate all your help on this.

I have two arrays:

  • the first array contains file names without an extension
  • the second array contains file names that have an extension.

I need to output a third array, in this case FinalArray that contains a list of all the ArrayFileNameWExt that are not in the ArrayFileName array.

I know I had a thread on finding matched items, which was great. But I'm having problems finding the unmatched items. I changed the == comparison to !== and that gave me one file name a hundred times.

Thank you for your help on this, Maxine

var ArrayFileName = ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];
var ArrayFileNameWExt = ['one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm'];
var FinalArray = [];

for (var i = 0; i < ArrayFileName.length; i++) {
    for (var j = 0; j < ArrayFileNameWExt.length; j++) {
        var temp = ArrayFileNameWExt[j].split(".");
        if(ArrayFileName[i]!==temp[0]){
            FinalArray.push(ArrayFileNameWExt[j]);
            break;
        }
    }
}
Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198
mightymax
  • 431
  • 1
  • 5
  • 16
  • So do you want a list of all the `ArrayFileNameWExt` that are not in the `ArrayFileName` array? – Nick Jan 17 '19 at 18:01
  • your filenames with extensions are always `\w+\.\w+`? – dquijada Jan 17 '19 at 18:01
  • Yes that's exactly what I'm looking for. – mightymax Jan 17 '19 at 18:02
  • Sometimes the file name has dashes and underscores in the name. but they always have a [.]ext – mightymax Jan 17 '19 at 18:02
  • Possible duplicate of [How to get the difference between two arrays in Javascript?](https://stackoverflow.com/questions/1187518/how-to-get-the-difference-between-two-arrays-in-javascript) – adiga Jan 17 '19 at 18:04
  • It's not a duplicate. The original post for finding matched items. This is to find unmatched items. I searched the forum but couldn't find a thread specific to my needs. – mightymax Jan 17 '19 at 18:07
  • It's not an exact duplicate but it's very similar. That question has many useful techniques and answers. Instead of directly comparing an element of second array, you'd have compare with filename without extension. Every answer posted below is just an improvement on [this answer](https://stackoverflow.com/a/33034768/3082296). Also, when someone in the future comes to this question looking at this title, they should see that popular question as linked/similar. – adiga Jan 17 '19 at 18:18

5 Answers5

4

You could use a simple filter and return all the items for which the first part of the split is not in the ArrayFileName array.

var ArrayFileName = ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];
var ArrayFileNameWExt = ['one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm'];

var final = ArrayFileNameWExt.filter(function(item) {
  return !ArrayFileName.includes(item.split('.')[0]);
})

console.log(final);

If you're using a pretty old version of javascript, the includes Array method might not exist. The following code could be used instead.

var ArrayFileName = ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];
var ArrayFileNameWExt = ['one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm'];

var final = ArrayFileNameWExt.filter(function(item) {
  var name = item.split('.')[0];
  for (var i = 0; i < ArrayFileName.length; i++) {
    if (ArrayFileName[i] === name) return false;
  }
  return true;
})

console.log(final);
Nick
  • 16,066
  • 3
  • 16
  • 32
  • The editor I have to use does not like the item=>. That's why I used the double loop above – mightymax Jan 17 '19 at 18:04
  • Well, => is standard and it works, your editor might be out of date – dquijada Jan 17 '19 at 18:04
  • 1
    The arrow function can simply be replaced by `function(item) { }` – Nick Jan 17 '19 at 18:05
  • Edited to replace arrow function with regular function if needed – Nick Jan 17 '19 at 18:06
  • Now the editor doesn't like return !ArrayFileName.includes(item.split('.')[0]); – mightymax Jan 17 '19 at 18:06
  • Out of curiosity, have you tried running the code either in node or browser? It sounds like your editor may not have its rules updated to current javascript standards, but node or your browser should be just fine. – Nick Jan 17 '19 at 18:08
  • I gave you one additional option if the `includes` method is what's giving your old version of js issues. – Nick Jan 17 '19 at 18:13
  • note this breaks for filenames like `a.b.ext` as your program will search for `a` instead of `a.b` – Mulan Jan 17 '19 at 18:18
  • I think that might go both ways though, what about extensions with periods in them (e.g., `.tar.gz`)? – Nick Jan 17 '19 at 18:20
  • @Nick this was great. Thank you for taking the time of giving me the second option. My editor works with it. – mightymax Jan 17 '19 at 18:27
  • 1
    @MaxineHammett no problem. I think someone else made the recommendation to try to upgrade your JS versions, which I would encourage you to do so as well. There are some really important features you'll be missing out on otherwise! – Nick Jan 17 '19 at 18:28
2

I would use .filter and .includes -

const fileNames =
  ['one', 'two', 'three', 'three', 'five', 'six', 'ten']

const fileNamesWExt =
  [ 'one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm' ]

const basename = filename =>
  filename.split(/\.[^.]+$/)[0]

const finalArray =
  fileNamesWExt.filter(f => ! fileNames.includes(basename(f)))
  
console.log(finalArray)
// [ 'eleven.cgm' ]

Note our implementation of basename, which is careful to only remove the last extension -

const basename = filename =>
  filename.split(/\.[^.]+$/)[0]
  
console.log
  ( basename ("cat")               // "cat"
  , basename ("cat.dog")           // "cat"
  , basename ("cat.dog.eel")       // "cat.dog"
  , basename ("cat.dog.eel.fox")   // "cat.dog.eel"
  )

If you cannot use arrow functions, you are probably using a pretty old version of JavaScript. In this case, you'll also need to polyfill .includes -

Array.prototype.includes = function (x, init) {
  for (var i = init || 0; i < this.length; i = i + 1)
    if (this[i] === x)
      return true;
  return false;
};

var fileNames =
  ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];

var fileNamesWExt =
  [ 'one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm' ];

var basename = function (filename) {
  return filename.split(/\.[^.]+$/)[0];
};

var finalArray =
  fileNamesWExt.filter(function (f) {
    return ! fileNames.includes(basename(f));
  });
  
console.log(finalArray);
// [ 'eleven.cgm' ]
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • The editor I'm using doesn't like the use of => with the filter method and results in an error – mightymax Jan 17 '19 at 18:05
  • Maxine, that's a pretty old version of JavaScript. I highly recommend working with a newer version as you're learning. My updated answer should help you out if you get stuck. – Mulan Jan 17 '19 at 18:11
  • @MaxineHammett, the IDE you use should have an option to change from EcmaScript5 (ES5) to ES6. Then the parsing errors will disappear. – Adrian Pop Jan 17 '19 at 18:18
  • It is an older version of Javascript. It saids the script succeeded but didn't give me any results. – mightymax Jan 17 '19 at 18:19
  • @MaxineHammett which editor are you using? `console.log` prints the result to stdout but it returns `undefined`. Maybe try adding `return finalArray` at the end of your script? – Mulan Jan 17 '19 at 18:20
2

Reusing the code you gave us, I made this: I interchanged the two for-loops and I used a variable (found) to keep track of the found items. Iterating through ArrayFileNameWExt in the outer loop is also better because we lower the number of calls to the split function.

var ArrayFileName = ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];
var ArrayFileNameWExt = ['one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm'];
var FinalArray = [];

for (var i = 0; i < ArrayFileNameWExt.length; ++i) {
    var temp = ArrayFileNameWExt[i].split(".");
    var found = false;
    
    for (var j = 0; j < ArrayFileName.length; ++j) {
        if (ArrayFileName[j] === temp[0]) {
            found = true;
            break;
        }
    }
    
    if (!found) {
        FinalArray.push(ArrayFileNameWExt[i]);
    }
}

console.log(FinalArray);

Cheers!

Adrian Pop
  • 1,879
  • 5
  • 28
  • 40
1

Array#filter lets you include (or delete) the elements that meet certain condition.

Array#inludes returns if certain element is included in the array.

String#split returns an array with the elements from splitting the string using the separator that you want (in this case, the point).

var ArrayFileName = ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];
var ArrayFileNameWExt = ['one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm'];
var FinalArray = [];

FinalArray = ArrayFileNameWExt.filter (filenameWExt => !ArrayFileName.includes(filenameWExt.split('.')[0]));

console.log(FinalArray);

Any further question let me know in the comments and I'll explain

dquijada
  • 1,697
  • 3
  • 14
  • 19
1

Perhaps Editor would like this

var ArrayFileName = ['one', 'two', 'three', 'three', 'five', 'six', 'ten'];
var ArrayFileNameWExt = ['one.txt', 'two.txt', 'three.txt', 'ten.wmf', 'eleven.cgm'];
var FinalArray = [];

for (var i = 0; i < ArrayFileNameWExt.length; i++) {

    var matchFound = false;
    for (var j = 0; j < ArrayFileName.length; j++) {
    
        var temp = ArrayFileNameWExt[i].split(".");
        
        if(ArrayFileName[j]==temp[0]){
            matchFound = true;
            break;
        }
    }
    if(!matchFound){
      FinalArray.push(ArrayFileNameWExt[i])
    
    }
    
}

console.log(FinalArray)