Может ли ES6 изначально кодировать перестановки над множеством в функциональной парадигме? - PullRequest
0 голосов
/ 03 мая 2020

Я хотел бы создать перестановки над Set (0..n) в Javascript.

Я борюсь с методами Array: некоторые из них, например map, возвращают новый массив, который может быть дальше модифицированный, другие как forEach нет. Чтобы кодировать перестановки, я мог сделать это только с улучшением прототипа Array:

Object.defineProperty(Array.prototype, "chain", {
  value: function(method, arg) {
    this[method].call(this, arg);
    return this;
  }
});

Object.defineProperty(Array.prototype, "value", {
  value: value => value // to value value ;-)
});

Только тогда я смог закодировать перестановки:

let perm = (n) =>
  n==0 ? [[0]] :
  perm(n-1).reduce((acc, cur) =>
    cur.chain("forEach", (_, i) =>
      acc.chain("push", [...cur.slice(0,i), n, ...cur.slice(i)])
    ).value(acc).chain("push", [...cur,n])
  ,[])

Тест:

console.log(perm(2));

Так возможно ли в ES6 (без добавления в прототип Array) кодировать перестановки над Set (или любым объектом, подобным массиву) чисто функциональным способом?

Я не хочу изнасиловать Javascript (как тогда делал jQuery), чтобы заставить его использовать какую-то ненативную парадигму, но я бы хотел полностью понять ее потенциал в функциональном поле.

1 Ответ

2 голосов
/ 04 мая 2020

ES6 вообще не нужен. Не следует использовать forEach или push, если вы хотите программировать в функциональном стиле - и скрывать их в методе chain, чтобы вы могли писать выражения с полезными возвращаемыми значениями, не помогает.

Вместо этого все, что вам нужно - это map и concat:

let perm = (n) =>
  n==0 ? [[0]] :
  perm(n-1).reduce((acc, cur) =>
    acc.concat(cur.map((_, i) =>
      [...cur.slice(0,i), n, ...cur.slice(i)]
    ), [[...cur,n]])
  , [])

Конечно, вы можете также заменить вызов concat на синтаксис с разбросом массива, если вы склонны.

...