0

I have an array containing many writing systems:

var SCRIPTS = [
  {
    name: "Adlam",
    ranges: [[125184, 125259], [125264, 125274], [125278, 125280]],
    direction: "rtl",
    year: 1987,
    living: true,
    link: "https://en.wikipedia.org/wiki/Fula_alphabets#Adlam_alphabet"
  },
  {
    name: "Han",
    ranges: [[11904, 11930], [11931, 12020], [12032, 12246], [12293, 12294], [12295, 12296], [12321, 12330], [12344, 12348], [13312, 19894], [19968, 40939], [63744, 64110], [64112, 64218], [131072, 173783], [173824, 177973], [177984, 178206], [178208, 183970], [183984, 191457], [194560, 195102]],
    direction: "ltr",
    year: -1100,
    living: true,
    link: "https://en.wikipedia.org/wiki/Chinese_characters"
  },
  // and many more entries
}

My task is to figure out to which writing system a character belongs:

scriptOfSample("英", SCRIPTS) // han

Here's my first appraoch, which is a working solution.

function scriptOfSample(a, scripts) {
    const codePoint = a.codePointAt(0)
    for (let language of scripts) {
        let isInRange = language.ranges.find(([from, to]) => from <= codePoint && codePoint <= to)
        if (isInRange) {
            return language.name
        }
    }

    return undefined
}

Out of curiosity I've tried to use an approach with the .forEach() method.

function scriptOfSample(a, scripts) {
    const codePoint = a.codePointAt(0)
    scripts.forEach(({ranges, name}) => {
        let isInRange = ranges.find(([from, to]) => from <= codePoint && codePoint <= to)
        if (Array.isArray(isInRange)) {
            console.log("found one")
            return name
        }
    })

    return undefined
}

However, in this case isInRange isn't a boolean value but contains the range [from, to] in which the predicate was true.

What I'd like to know:

  1. Why is the find() method returning different values?
  2. What can I do (How do I have to adjust my implementation), to check if value "is in range"?
Beru
  • 657
  • 1
  • 6
  • 21
  • 2
    [`.find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) always returns an item from the array or `undefined` if it doesn't find one. That is its purpose. It takes a predicate (a function that returns a boolean) *in order to know which item to return*. It wouldn't really be called "find" if you would give it a predicate and didn't find an item for you. You probably want [`.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) which tests the predicate and tells you if at least one item matches it. – VLAZ Dec 05 '21 at 15:18
  • Also, did you [check what `isInRange` is in your first piece of code](https://jsbin.com/jupepiwazu/1/edit?js,console)? Why do you say it's *not* an array (since you contrast it with the second one where it is)? – VLAZ Dec 05 '21 at 15:23
  • 1
    @VLAZ So in both cases `.find()` returns the first item and since `[from, to]` inside an if-condition is truthful both checks work. The problem would be then, that inside my `.forEach()` I can't return anything. Right? – Beru Dec 05 '21 at 15:23
  • 1
    [Why does this forEach return undefined when using a return statement](https://stackoverflow.com/q/7209794) | [Function with forEach returns undefined even with return statement](https://stackoverflow.com/q/16392445) | [Short circuit Array.forEach like calling break](https://stackoverflow.com/q/2641347) | [What does `return` keyword mean inside `forEach` function?](https://stackoverflow.com/q/34653612) – VLAZ Dec 05 '21 at 15:28

1 Answers1

1

The comments are correct in saying that Array#find returns an element of the array or undefined. Since you're calling it on ranges which is an array of arrays, you get an array back.

You can use the Array#some method instead, which returns a boolean if the condition is met on any item of the array:

function scriptOfSample(a, scripts) {
    const codePoint = sample.codePointAt(0);

    if (codePoint == null) return undefined

    const system = scripts.find(
        (script) => script.ranges.some(
            ([from, to]) => from <= codePoint && codePoint <= to
        )
    );

    return system ? system.name : undefined
}
emeraldsanto
  • 4,330
  • 1
  • 12
  • 25