4

I need to return the index of the odd word out in an array of words(strings).

For example...

['junper', 'jumper'] should return 0 
['Jumper'] should return 0 
['coast', 'coast', 'coal', 'coast'] should return 2
['sofa', 'sofa', 'sofa', 'soft'] should return 3

I already have a worked solution but I am aiming to make this cleaner.

I have been thinking about whats the best way to go about returning the index of the word which occurs only once...

This is my aforementioned working solution:

function findWrongWord(householditems) {
    if (householditems.length < 3) return 0;

    function findOccurencesLength (array, toEqual) {
        return array.filter(x => x === toEqual).length
    }

    let copyOfInitialArray = [...householditems];
    let [, mostOccuredItem = ''] = copyOfInitialArray.sort((a, b) => 
        findOccurencesLength(copyOfInitialArray, a) - 
        findOccurencesLength(copyOfInitialArray, b));

    return householditems.findIndex(x => x === 
        mostOccuredItem.split('').reverse().join(''));
}
8
  • 3
    Why should ['coat', 'coast', 'coal', 'coast'] return 2? Commented May 14, 2019 at 16:00
  • By odd word you mean the string with odd length? Commented May 14, 2019 at 16:02
  • fixed marie - thanks! Commented May 14, 2019 at 16:03
  • hi maheer, not length, it can be any length but essentially returning the index of the word which occurs only once :) Commented May 14, 2019 at 16:03
  • @CL91 You mean the first element which is not repeated in array? Commented May 14, 2019 at 16:04

5 Answers 5

2

If you want to find one word that only appears once on the array, maybe you can use a combination of Array.findIndex() and Array.filter(), like this:

const tests = [
  ['junper', 'jumper'],
  ['Jumper'],
  ['coast', 'coast', 'coal', 'coast'],
  ['sofa', 'sofa', 'sofa', 'soft']
];

const getIndex = (arr) =>
{
    return arr.findIndex(word => arr.filter(x => x === word).length === 1);
}

tests.forEach(
    test => console.log(`${test} -> ${getIndex(test)}`)
);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Another approach is to first use Array.reduce() to generate a Map() with the frequencies of each word, and then find the first word with frequency 1.

const tests = [
  ['junper', 'jumper'],
  ['Jumper'],
  ['coast', 'coast', 'coal', 'coast'],
  ['sofa', 'sofa', 'sofa', 'soft']
];

const getIndex = (arr) =>
{
    let freq = arr.reduce((acc, word) =>
    {        
        acc.set(word, acc.has(word) ? acc.get(word) + 1 : 1);
        return acc;
    }, new Map())

    return arr.findIndex(word => freq.get(word) === 1);
}

tests.forEach(
    test => console.log(`${test} -> ${getIndex(test)}`)
);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Sign up to request clarification or add additional context in comments.

Comments

2

You can compare indexOf and lastIndexOf to check if element is repeated.

const nonRepeated = arr => arr.findIndex(x => arr.indexOf(x) === arr.lastIndexOf(x))

console.log(nonRepeated(['junper', 'jumper']))
console.log(nonRepeated(['Jumper'] ))
console.log(nonRepeated(['coast', 'coast', 'coal', 'coast']))
console.log(nonRepeated(['sofa', 'sofa', 'sofa', 'soft']))

Another way is to use an object get count of all the elements and then return the first of those whose count is 1.

const nonRepeated = arr => {
  let countObj = arr.reduce((ac,a,i) => {
    if(!ac[a]) ac[a] = {count:0,index:i};
    ac[a].count++;
    return ac;
  },{})
  return Object.values(countObj).find(x => x.count === 1).index;

}
console.log(nonRepeated(['junper', 'jumper']))
console.log(nonRepeated(['Jumper'] ))
console.log(nonRepeated(['coast', 'coast', 'coal', 'coast']))
console.log(nonRepeated(['sofa', 'sofa', 'sofa', 'soft']))

Comments

0

try (where h={})

a.indexOf(a.map(e=>(h[e]=++h[e]|0,e)).find(w=>!h[w]));

let test = [
  ['junper', 'jumper'],
  ['Jumper'],
  ['coast', 'coast', 'coal', 'coast'],
  ['sofa', 'sofa', 'sofa', 'soft'],
];

function findWrongWord(a) {
  let h={};
  return a.indexOf(a.map(w=>(h[w]=++h[w]|0,w)).find(w=>!h[w]));
}

test.map(t=> console.log(JSON.stringify(t),findWrongWord(t)));

Comments

0

One idea is to use a map to maintain a list of index position and count, Next sort, and then unshift the first item.

Below is a working snippet.

const oddOne = arr => 
  arr.map((m,i,a) => (
    {i, c: a.filter(f => f === m).length})
  ).sort((a,b) => a.c - b.c).shift().i;
  
const tests = [
  ['junper', 'jumper'],
  ['Jumper'],
  ['coast', 'coast', 'coal', 'coast'],
  ['sofa', 'sofa', 'sofa', 'soft']
];

for (const test of tests) {
  console.log(JSON.stringify(test), "=", oddOne(test));
}

Comments

0

First I'll make an assumption, you already know that there is only one "odd" word in the array. My javascript is not good so I'll put it down in words. Its not the most beautiful solution but is logical

  1. Create an array of integers with the same length as the array you want to test. Each element in this array will represent the number of times the corresponding word in the array you are testing appears.

    Array appearances = new Array(testArray.length);
    // instantiate all element to zero
    
  2. For each element in the test array, test if it is equal to the element at position 1, 2, 3,...last position, increment each by one where they are equal

    for (int i = 0; i < testArray.length; i++) {
        for(testWord in testArray) {
            if(word == testWord) {
               appearances[i] = appearances[i]++;
            }
    
            // we don't really need to know the exact number of times it appears, just knowing it appears more than once is enough
            if(appearances[i] ==2) {
                break;
            }
        }
    }
    
  3. Now we find 1 in the appearances array I think array.find() is the way, it index will also be the index of the word not similar to others.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.