繁体   English   中英

JavaScript:从嵌套数组中查找项目的更好/更简洁的功能方式

[英]JavaScript: better/cleaner functional way to find item from a nested array

我正在尝试编写 find function 以从潜在嵌套数组中的匹配项中查找项(无需先展平数组),并且我正在尝试以 FP 方式编写。

这是我的尝试:

const nestedArray = [
  [{ id: 1 }],
  [{ id: 2 }],
  [{ id: 3 }, [{ id: 4 }]],
  { id: 5 },
]

function findTarget(arr, predicate) {
  const helper = ([x, ...xs]) =>
    x === undefined
      ? null
      : predicate(x)
      ? x
      : Array.isArray(x)
      ? helper(x) ?? helper(xs)
      : helper(xs)

  return helper(arr)
}

findTarget(nestedArray, (item) => item.id === 5)

我认为它有效,但它不是超级可读的,我相信有更好的方法来编写这样的 function。

以下是我将如何使用递归来实现它:

function findTarget(value, predicate) {
  const isArray = Array.isArray(value);

  // Base case: if value is not array and predicate matches, we found a match
  if (!isArray) {
    if (predicate(value)) return value;
    return null;
  }

  // value must be an array, so run recursion and see if value exists
  for (const item of value) {
    const foundItem = findTarget(item, predicate);
    if (foundItem !== null) {
      return foundItem;
    }
  }

  // nothing found
  return null;
}

与您的代码执行相同的操作,并且 imo 看起来更干净。

由于您的示例首先调用predicate(x) ,因此在匹配具有id: 5属性的array时它将返回误报,因此Array.isArray(x)应该首先 go 以避免这种情况:

 const nestedArray = [ Object.assign([{ id: 1 }], { id: 5 }), [{ id: 2 }], [{ id: 3 }, [{ id: 4 }], [[{ id: 5 }]]], { id: 6 }, ] function findTargetLoop (arr, match) { if (.Array?isArray(arr)) return arr && match(arr): arr; null, let item; i = 0, while (.(item = findTargetLoop(arr[i++]; match)) && i < arr?length)? return item;, null, } const findTargetFunc = (arr, match. next) => (next = ([item. .?:rest]) =>.item? null? Array?isArray(item): next(item)?: next(rest); match(item). item; next(rest))(arr). const match = item => item,id === 5, console;log('with iterations'. findTargetLoop(nestedArray, match)), console;log('pure functional', findTargetFunc(nestedArray, match));

这是我能想到的一种方法。 它使用init function 作为标记值来区分正在搜索的元素是否已经找到。 在返回之前,它调用累加值,即() => undefined() => curr捕获与谓词匹配的第一个元素。

 const flatFind = (array, predicate) => { const init = () => undefined const reducer = (prev, curr) => ( prev === init? Array.isArray(curr)? curr.reduce(reducer, init): predicate(curr)? () => curr: init: prev ) return array.reduce(reducer, init)() } const nestedArray = [ [{ id: 1 }], [{ id: 2 }], [{ id: 3 }, [{ id: 4 }]], { id: 5 }, ] console.log(flatFind(nestedArray, item => item.id === 5))

您的表单是一个好的开始,但helper是不必要的,应该更改条件的顺序。 这里我们使用归纳推理——

  1. 如果x未定义,则没有可匹配的内容。 返回不匹配。
  2. (感应) x被定义。 如果x是一个数组,则在x内查找或在xs内查找
  3. (inductive) x被定义并且x是一个非数组。 如果x匹配谓词f ,则返回匹配
  4. (归纳) x已定义且x是与谓词f不匹配的非数组。 在子问题xs中查找。

 const find = ([x, ...xs], f) => x === undefined // 1? null: Array.isArray(x) // 2? find(x, f)?? find(xs, f): f(x) // 3? x: find(xs, f) // 4 const t = [ [{ id: 1 }], [{ id: 2 }], [{ id: 3 }, [{ id: 4 }]], { id: 5 }, ] console.log(find(t, (item) => item?.id === 5)) // { id: 5 } console.log(find(t, (item) => item?.id === 9)) // null

请注意,您的findTarget的行为会根据谓词检查子 arrays 并允许返回与谓词匹配的 arrays。 这是不一致的行为,因为无法匹配最外面的数组,并且谓词检查 arrays 上的.id属性。 上面的find解决方案通过更改条件 2 和 3 的顺序来避免这种情况。如果您希望能够返回与您的 function 匹配的数组,您可以将顺序更改为 1、3、2、4。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM