2017-10-10 2 views
4

Compte tenu des tableaux suivants:carte emboîtés de tableaux de la façon dont FP

const array1 = ["a1", "b1", "c1", "d1"], 
     array2 = ["a2", "b2"], 
     array3 = ["a3", "b3", "c3"] 

Y at-il fonction pour simplifier Ramda le scénario suivant sur lequel je pourrais donner un ou plusieurs tableaux?

const nestedMap = map => { 
    const result = [] 

    for(let item1 of array1) 
     for(let item2 of array2) 
      for(let item3 of array3) 
        result.push(map(item1, item2, item3)) 
    return result 
} 

fonction entière regarderait comme suit:

// Sample usage 
nestedMap((item1, item2, item3) => `${item1} ${item2} ${item3}`, array1, array2, array3) 

Je cherche à éviter de réinventer la roue.

Remarque: Vanilla javascript ou toute autre bibliothèque peut être acceptable. J'ai d'abord parlé de Ramda car il a beaucoup de fonctions et peut-être que j'ai manqué ce qui pourrait aider à résoudre ce problème

+0

donc, essentiellement nous recherchons une formation de matrice. Correct? Il serait utile si vous pouvez également ajouter un exemple de sortie. De plus, les fonctions JS sont-elles acceptables? – Rajesh

+0

Puisque vous posez des questions sur la programmation fonctionnelle: pourquoi votre fonction n'a-t-elle pas de valeur de retour? Je ne vois pas de 'map'ping qui se passe ici, cela ressemble plus à un' forEach' multidimensionnel avec un callback. – Bergi

+0

Ceci est appelé le [produit cartésien] (https://stackoverflow.com/a/15310051/1048572) – Bergi

Répondre

5

Vous pouvez utiliser la instance applicative pour les tableaux ici simplement R.lift votre fonction:

const array1 = ["a1", "b1", "c1", "d1"], 
 
     array2 = ["a2", "b2"], 
 
     array3 = ["a3", "b3", "c3"] 
 

 
const nestedMap = R.lift((item1, item2, item3) => `${item1} ${item2} ${item3}`) 
 

 
console.log(nestedMap(array1, array2, array3))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

+0

c'est vraiment bien. –

+0

Ceci est la * réponse: D –

+0

J'ai une question: comment un tableau satisfait la spécification d'application de FantasyLand? –

2

Vous pouvez utiliser une approche en deux étapes,

  1. construire tous les produits
  2. mappe la fonction.

const 
 
    nestedMap = (fn, ...array) => array 
 
     .reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), [])) 
 
     .map(a => fn(...a)), 
 
    array1 = ["a1", "b1", "c1", "d1"], 
 
    array2 = ["a2", "b2"], 
 
    array3 = ["a3", "b3", "c3"], 
 
    result = nestedMap((item1, item2, item3) => `${item1} ${item2} ${item3}`, array1, array2, array3) 
 

 
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

3

Ramda a une fonction xprod qui donne la liste des deux produits croisés. Il est relativement facile de l'étendre à plusieurs listes comme ceci:

const xproduct = R.reduce(R.pipe(R.xprod, R.map(R.unnest)), [[]]) 

Ensuite, nous pouvons l'utiliser pour créer la fonction de carte imbriquée relativement facilement:

const array1 = ["a1", "b1", "c1", "d1"], 
 
     array2 = ["a2", "b2"], 
 
     array3 = ["a3", "b3", "c3"] 
 

 
const xproduct = R.reduce(R.pipe(R.xprod, R.map(R.unnest)), [[]]) 
 
const nestedMap = (fn, ...arrs) => R.map(R.apply(fn), xproduct(arrs)) 
 

 
console.log(nestedMap((a, b, c) => `${a}-${b}-${c}`, array1, array2, array3)) 
 
//==> ["a1-a2-a3", "a1-a2-b3", ...]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

1

comment cela fonctionne

Cette réponse vous donne un aperçu sur la façon dont @ la réponse de ScottChristopher travaille en vous montrant .ap (et .chain) mis en œuvre directement sur le prototype de Array-comme un exercice ! Ne pas paniquer, fanatiques prototypes ...

L'idée est ici de démontrer le comportement objectif/sortie dans un extrait de code qui vous montre toutes les des pièces mobiles à la fois.Avec seulement ~ 8 lignes de code à comprendre, le facteur d'intimidation est assez faible; par rapport à quelque chose comme creuser dans la source Rambda (qui est en fait assez agréable)

J'ai récemment partagé another answer J'ai fait quelque chose de très similaire en utilisant des continuations délimitées - si cette réponse vous intéresse, je pense que vous apprécierez aussi cette lecture un^_^

// Array Applicative 
 
Array.prototype.ap = function (...args) 
 
    { 
 
    const loop = (acc, [x,...xs]) => 
 
     x === undefined 
 
     ? [ this [0] (...acc) ] 
 
     : x.chain (a => 
 
      loop (acc.concat ([a]), xs)) 
 
    return loop ([], args) 
 
    } 
 
    
 
// Array Monad 
 
Array.prototype.chain = function chain (f) 
 
    { 
 
    return this.reduce ((acc, x) => 
 
     acc.concat (f (x)), []) 
 
    } 
 

 
const array1 = ['a1', 'b1', 'c1', 'd1'] 
 
const array2 = ['a2', 'b2'] 
 
const array3 = ['a3', 'b3', 'c3'] 
 

 
console.log ([ (x,y,z) => [x,y,z] ] .ap (array1, array2, array3)) 
 
// [ [ 'a1', 'a2', 'a3' ], 
 
// [ 'a1', 'a2', 'b3' ], 
 
// [ 'a1', 'a2', 'c3' ], 
 
// [ 'a1', 'b2', 'a3' ], 
 
// [ 'a1', 'b2', 'b3' ], 
 
// [ 'a1', 'b2', 'c3' ], 
 
// [ 'b1', 'a2', 'a3' ], 
 
// [ 'b1', 'a2', 'b3' ], 
 
// [ 'b1', 'a2', 'c3' ], 
 
// [ 'b1', 'b2', 'a3' ], 
 
// [ 'b1', 'b2', 'b3' ], 
 
// [ 'b1', 'b2', 'c3' ], 
 
// [ 'c1', 'a2', 'a3' ], 
 
// [ 'c1', 'a2', 'b3' ], 
 
// [ 'c1', 'a2', 'c3' ], 
 
// [ 'c1', 'b2', 'a3' ], 
 
// [ 'c1', 'b2', 'b3' ], 
 
// [ 'c1', 'b2', 'c3' ], 
 
// [ 'd1', 'a2', 'a3' ], 
 
// [ 'd1', 'a2', 'b3' ], 
 
// [ 'd1', 'a2', 'c3' ], 
 
// [ 'd1', 'b2', 'a3' ], 
 
// [ 'd1', 'b2', 'b3' ], 
 
// [ 'd1', 'b2', 'c3' ] ]