0

I'm trying to solve this task of finding the unique element inside an array. So far I managed to solve 95%, but I'm failing on 0. I get an error saying that expected 0 and got 1.

I should get //10, which it does, but after I'm failing the test online. For all other values it has passed.

Any ideas about how to solve this and what I'm missing here?

function findOne(arr) {
  let x = arr[0];
  for (let i of arr) {
    if (i === x) {
      continue;
    } else {
      x = i;
    }
    return x;
  }
}
console.log(findOne([3, 10, 3, 3, 3]));
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Tiago Ruivo
  • 183
  • 1
  • 9

5 Answers5

0

I don't really understand your code. You start with the first value in the array, then you loop through the array, skipping anything that's the same, and then return the first one that's not the same. That won't find unique values, it'll just find the first value that doesn't equal the first value. So for instance, try it on the array [1,2,2,2,2] and you'll get a result of 2 instead of 1, even though that's clearly wrong.

Instead, you can create a map of each value and its incidence, then filter by the ones that equal 1 at the end.

function findOne(arr) {
    const incidences = arr.reduce((map, val) => {
      map[val] = (map[val] || 0) + 1;
      return map;
    }, {});
    const values = Object.keys(incidences);
    for (let i = 0; i < values.length; ++i) {
      if (incidences[values[i]] === 1) { return values[i]; }
    }
    return null;
}

EDIT The above won't preserve the type of the value (i.e. it'll convert it to a string always, even if it was originally a number). To preserve the type, you can use an actual Map instead of an object:

function findOne(arr) {
    const incidences = arr.reduce((map, val) => {
      map.set(val, (map.get(val) || 0) + 1);
      return map;
    }, new Map());
    const singletons = Array.from(incidences).filter(entry => entry[1] === 1);
    return singletons.map(singleton => singleton[0]);
}
IceMetalPunk
  • 5,476
  • 3
  • 19
  • 26
  • No problem, I'm just trying to help you learn :) I also realized my original code would change all values to string, so I added another version that uses actual Maps to preserve the types. (It returns an array of all unique values, or an empty array if there are none.) The idea is that for every value, you set the map for that value to 0 if it's not been seen before, or use the current value; then add 1. This gives you a map of all values and how often they appear; then you look for the one that appears exactly once and return that. – IceMetalPunk Oct 29 '19 at 15:32
  • It fails... Also it's quite complex for me to understand your code. Passing the exam it's not the most important. I need to understand my solutions too... – Tiago Ruivo Oct 29 '19 at 15:38
  • How does it fail? I tested it with the input array [0,1,1,2,2,3,3] and it returns the result array `[0]` which is correct as 0 is the only duplicated value. (I tried to explain the code in my previous comment; if there's anything you don't understand about it, feel free to ask! :) ) – IceMetalPunk Oct 29 '19 at 15:39
  • It fails : I got: Expected: 1, instead got: [1] Expected: 2, instead got: [2] Expected: 10, instead got: [10] which is not much info but it's not passing... – Tiago Ruivo Oct 29 '19 at 15:45
  • As I said, it returns an array of the unique values (denoted by the `[]` brackets around them); looks like the test is expecting just the value without the array. So you can just return the first array element of the result instead of the entire array, and it will work fine for those only-one-unique-value cases. – IceMetalPunk Oct 29 '19 at 15:48
  • did this: ```const singletons = Array.from(incidences).filter(entry => entry[1] === 1); singletons.map(singleton => singleton[0]); return singletons[0]; ``` and now I'm getting an array of [10, 1]. So we are close.. – Tiago Ruivo Oct 29 '19 at 15:55
  • The Array `map` function doesn't modify the original array, it returns a new one with the values mapped. So just return the result of the map function (and select index 0 from it), or save it in a new variable and return index 0 of that variable :) – IceMetalPunk Oct 29 '19 at 15:57
0

Consider the following:

Recall that a span = max - min + 1;

Let Partition P1 be span from 0..span-1;

Let Partition P2 be span from span..(2*span)-1:

Place a number in P1 if it is not in P2.

Place a number in P2 if it is already in P1.

Once the number is in P2, do not consider it again.

If a number is in P1 then it is unique.

C. R. Ward
  • 93
  • 5
-1

You can get all values that appear once, by using a map to count how many times each element has appeared. You can then reduce that map into an array of unique values:

const findUnique = arr => {
  const mapEntries = [...arr.reduce((a, v) => a.set(v, (a.get(v) || 0) + 1), new Map()).entries()]
  return mapEntries.reduce((a, v) => (v[1] === 1 && a.push(v[0]), a), [])
}

console.log(findUnique([3, 10, 3, 3, 3]))
console.log(findUnique([1, 2, 3, 2, 4]))
console.log(findUnique([4, 10, 4, 5, 3]))

If you don't care about multiple unique values, you can just sort the array and use logic, rather than checking every value, provided the array only contains 2 different values, and has a length greater than 2:

const findUnique = arr => {
  a = arr.sort((a, b) => a - b)
  if (arr.length < 3 || new Set(a).size === 1) return null
  return a[0] === a[1] ? a[a.length-1] : a[0]
}

console.log(findUnique([3, 10, 3, 3, 3]))
console.log(findUnique([3, 3, 1]))
console.log(findUnique([3, 1]))
console.log(findUnique([3, 3, 3, 3, 3]))
Kobe
  • 6,226
  • 1
  • 14
  • 35
  • You should document your code. You've introduced a host of new concepts (`reduce`, `Set`, `Map` etc) that the OP might not necessarily understand. – Andy Oct 29 '19 at 15:47
  • This did the it, however It's quite advanced for me to understand all the variables... Could you explain step by step after the sorted array? – Tiago Ruivo Oct 29 '19 at 15:59
  • @TiagoRuivo which version did you use? I'll try my best to explain it. – Kobe Oct 29 '19 at 16:00
  • the second one... Maybe if you clarify your code for more simpler JS. More descriptive kind of... – Tiago Ruivo Oct 29 '19 at 16:01
  • @TiagoRuivo First, I sort the array so that they are all in order, it doesn't matter what order, as long as duplicates are next to each other. For example [2, 3, 2] would sort to [2, 2, 3]. Then we check if the first value is equal to the second value. We know if it's the same, then the last value will be the unique value, since there are only two different types of values. Otherwise, if the first two weren't the same, then the first value is the non dupe. The if statement is to check is to check if the array is longer than 2 elements long, which is a must, otherwise both could be unique. – Kobe Oct 29 '19 at 16:04
  • The set is to check if all the values aren't the same value. When we create a set, all duplicates are removed. If there's a length of 2, then we know there are two different values, otherwise, there will be a length of one, meaning they are all duplicates – Kobe Oct 29 '19 at 16:06
  • @TiagoRuivo No worries. Logic can be more fun to write than fancy O(n) code sometimes :P – Kobe Oct 29 '19 at 16:11
  • I'm referring to [time complexity](https://en.wikipedia.org/wiki/Time_complexity), or how fast code operates. – Kobe Oct 29 '19 at 16:17
  • quite easy to see that it will fail for example with `[3, 10, 3, 3, 3, 10, 4]`, talking about the second one – fedeghe Oct 29 '19 at 16:48
  • @fedeghe "provided the array only contains 2 different values". That's the point of the second example. – Kobe Oct 30 '19 at 10:37
  • @fedeghe no worries. – Kobe Oct 30 '19 at 11:22
-1

Your code is complex, Try this

function findOne(arr) {
  const uniqueItems = [];
  arr.forEach(item => {
    const sameItems = arr.filter(x => x === item);
    if (sameItems.length === 1) {
      uniqueItems.push(item);
    }
  });

  return uniqueItems;
}
console.log(findOne([0, 1, 1, 3, 3, 3, 4]));

I'm getting all unique items from passed array, It may have multiple unique item

  • It doesn't pass either... It failed harder than my solution... I only have one unique int ... – Tiago Ruivo Oct 29 '19 at 15:36
  • 1
    @TiagoRuivo I just tested and it does work; it returns an array of the unique values. You can take the first entry of the result if you only want to check for one. – IceMetalPunk Oct 29 '19 at 15:37
  • 2
    While this works, the filter inside the forEach means it's running at O(n^2) efficiency, which is much slower than it needs to be... – IceMetalPunk Oct 29 '19 at 15:38
  • This is the task: There is an array with some numbers. All numbers are equal except for one. Try to find it! findUniq([ 1, 1, 1, 2, 1, 1 ]) === 2 findUniq([ 0, 0, 0.55, 0, 0 ]) === 0.55 It’s guaranteed that array contains more than 3 numbers. – Tiago Ruivo Oct 29 '19 at 15:40
-1

this is a way simpler and fast:

function findOne(arr) {
  const a = arr.reduce((acc, e) => {
    e in acc || (acc[e] = 0)
    acc[e]++
    return acc
  }, {})
  return Object.keys(a).filter(k => a[k] === 1)[0] || null
}
fedeghe
  • 1,243
  • 13
  • 22