1

I have 2 questions, how can I get value instead of value inside array and how can I make this code shorter and declarative.

arr = [16, 4, 11, 20, 2]

arrP = [7, 4, 11, 3, 41]

arrTest = [2, 4, 0, 100, 4, 7, 2602, 36]

function findOutlier(arr) {
  const isPair = (num) => num % 2 === 0
  countEven = 0
  countOdd = 0
  arr1 = []
  arr2 = []
  const result = arr.filter((ele, i) => {
    if (isPair(ele)) {
      countEven++
      arr1.push(ele)

    } else {
      countOdd++

      arr2.push(ele)
    }

  })
  return countEven > countOdd ? arr2 : arr1

}

console.log(findOutlier(arrTest))
epascarello
  • 204,599
  • 20
  • 195
  • 236
foxDev
  • 87
  • 7
  • 2
    Can you clarify what you're trying to do? It is hard for me to understand what result you're looking for. – Nick Dec 31 '20 at 15:14
  • Are you trying to split an array into an `even` array and an `odd` array, and then return the longer one? – Nick Dec 31 '20 at 15:16
  • Isn't the ternary backwards? What is the expected output? – epascarello Dec 31 '20 at 15:16
  • What should the function return when neither odds nor evens are just one, like [1, 3, 2, 4, 6]? Also the title seems to ask for a string output ("even", "odd"), but that is not what your code is doing... can you clarify? – trincot Dec 31 '20 at 15:18
  • @derpirscher um, I know how a ternary works... – epascarello Dec 31 '20 at 15:21
  • The arrays are reversed. It is returning the odd when even is greater. – epascarello Dec 31 '20 at 15:23
  • Ah, sorry for the misunderstanding ... – derpirscher Dec 31 '20 at 15:24
  • 1
    will there only ever be one element that is not the same as the rest? – pilchard Dec 31 '20 at 15:33
  • @epascarello Since the function is named `findOutlier` I assume the intent is to return the smallest of the two. *"outlier: a fact, figure, piece of data, etc. that is very different from all the others in a set and does not seem to fit the same pattern"* - [Cambridge English Dictionary](https://dictionary.cambridge.org/dictionary/english/outlier) – 3limin4t0r Dec 31 '20 at 16:29
  • this is the exercice: You are given an array (which will have a length of at least 3, but could be very large) containing integers. The array is either entirely comprised of odd integers or entirely comprised of even integers except for a single integer N. Write a method that takes the array as an argument and returns this "outlier" N. – foxDev Dec 31 '20 at 18:35
  • @foxDev You should have added this excercise description to the question. – derpirscher Dec 31 '20 at 18:59

6 Answers6

1

Filtering twice may be more readable.

even = arr.filter((x) => x % 2 == 0);
odd = arr.filter((x) => x % 2 == 1);
if (even.length > odd.length) {
    return even;
} else {
    return odd;
}
LightFelicis
  • 129
  • 1
  • 5
0

If you're looking to do this with one loop, consider using the array reduce method to put each number into an even or odd bucket, and then compare the length of those buckets in your return:

function findOutlier(arr) {
  const sorted = arr.reduce((acc, el) => {
    acc[el % 2].push(el);
    return acc;
  },{ 0: [], 1: [] })
  
  return sorted[0].length > sorted[1].length ? sorted[1] : sorted[0];
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(findOutlier(arr));

Note that this does not handle when the arrays are the same length gracefully (right now it'll just return the odd array).

Nick
  • 16,066
  • 3
  • 16
  • 32
0

Now that OP clarified the requirements (at least in a comment) this allows a different approach:

function findOutlier(array) {
  let odd = undefined, even = undefined;

  for (let i of array) {
    let isEven = i % 2 == 0;
  
    if (odd !== undefined && even !== undefined)
      return isEven ? odd : even;

    if (isEven) even = i;
      else odd = i;
  }
  
  if (odd !== undefined && even !== undefined)
    return array[array.length-1];
}
    
    
console.log(findOutlier([2,4,6,8,10,5]))

The algorithm will iterate the array, and store the lastest found odd and even numbers, respectively.

If we discovered both an odd and an even number already, with the current number we can decide, which of them is the outlier: If the current number is even, it's at least the second even number we found. Thus, the found odd number must be the outlier. The same applies vice versa if the current number is odd. The special case, if the outlier is the last element of the array, is checked with an additional condition after the loop.

If all numbers are odd or even (ie there is no outlier) this function will return undefined. This algorithm does not throw an error, if the preconditions are not met, ie if there is more than one outlier.

derpirscher
  • 14,418
  • 3
  • 18
  • 35
0

You could take an object with the wanted part for collecting and add a short circuit if one of the types has a count of one and the others have a count greater than one.

const
    isPair = num => num % 2 === 0,
    findOutlier = array => {
        count = { true: [], false: [] };
        for (const value of array) {
            count[isPair(value)].push(value);
            if (count.true.length === 1 && count.false.length > 1) return count.true[0];
            if (count.false.length === 1 && count.true.length > 1) return count.false[0];
        }
    };

console.log(...[[16, 4, 11, 20, 2], [7, 4, 11, 3, 41], [2, 4, 0, 100, 4, 7, 2602, 36]].map(findOutlier));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Here is an solution that selects the even or odd array based on the modulo result.

function findOutlier(integers) {
  const even = [], odd = [], modulos = [even, odd];
  for (const integer of integers) {
    modulos[Math.abs(integer % 2)].push(integer);
  }
  return even.length > odd.length ? odd : even;
}

console.log(findOutlier([2, 4, 0, 100, 4, 7, 2602, 36]));

You unfortunately do need Math.abs() to handle negative values, because -3 % 2 == -1.

See: JavaScript % (modulo) gives a negative result for negative numbers

However the name findOutlier lets me assume there is only a single outlier within the provided list. If this is the case you can optimize the algorithm.

function findOutlier(integers) {
  // With less than 3 integers there can be no outlier.
  if (integers.length < 3) return;
  
  const isEven = (integer) => integer % 2 == 0;
  const isOdd  = (integer) => !isEven(integer);
  
  // Determine the outlire based on the first 3 elements.
  // If there are 0 or 1 integers even, the outlire is even.
  // if there are 2 or 3 integers even, the outlier is odd.
  const outlier = integers.slice(0, 3).filter(isEven).length < 2
                ? isEven
                : isOdd;

  return integers.find(outlier);
}

console.log(findOutlier([2, 4, 0, 100, 4, 7, 2602, 36]));
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
0

You can do this without creating intermediate arrays by simply comparing each element to its neighbors and returning that element if it is different to both, or undefined if no outliers are found. This returns in the same iteration in which the outlier is first encountered, and returns the value itself and not an array.

function findOutlier(array) {
  const
    len = array.length,
    isEven = (n) => n % 2 === 0;

  for (const [i, value] of array.entries()) {
    let
      prev = array[(i-1+len)%len], // loop around if < 0 (first element)
      next = array[(i+1)%len];     // loop around if >= length (last element)
    if (isEven(value) !== isEven(prev) && isEven(value) !== isEven(next)) {
      return value;
    }
  }
  return undefined;
}

const arrays = [[16, 4, 11, 20, 2], [7, 4, 11, 3, 41], [2, 4, 0, 100, 4, 7, 2602, 36]]
console.log(...arrays.map(findOutlier));
pilchard
  • 12,414
  • 5
  • 11
  • 23