1
votes

Filtrer et mapper un tableau avec Ramda

J'utilise Ramda pour obtenir les équipes avec 'Prem League' dans leur tableau de catégories. Mon code ressemble à ce qui suit et il fonctionne.

filter(prop('categories').includes('Prem League')),

Cependant, je souhaite supprimer team comme argument pour le filtre et la map .

J'ai essayé ce qui suit mais j'ai obtenu prop (...). includes is not a function

import { pipe, map, filter } from 'ramda'   

const teams = [
  {name: 'Liverpool', id: '1', categories: ['Prem League']},
  {name: 'Man Utd', id: '2', categories: ['Blue Square']},
  {name: 'Sheff Utd', id: '2', categories: ['Prem League']},
]

const getTeamOptions = pipe(
    filter((team) => team.categories.includes('Prem League')),
    map((team) => ({ label: team.name, value: team.id }))
);

getTeamOptions(teams)

Idéalement, j'essaierais et supprimez également team de map , mais ce n'est peut-être pas nécessaire.

La raison de ces changements est que je suis ce cours et il conseille prop etc. comme meilleures pratiques .


0 commentaires

5 Réponses :


1
votes

Vous pouvez utiliser R.includes pour vérifier l'existence de la valeur. Vous pouvez générer le nouvel objet en utilisant R.applySpec:

<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
const { pipe, filter, prop, includes, map, applySpec } = R;

const getTeamOptions = val => pipe(
  filter(pipe(prop('categories'), includes(val))),
  map(applySpec({ label: prop('name'), value: prop('id') }))
);

const teams = [{"name":"Liverpool","id":"1","categories":["Prem League"]},{"name":"Man Utd","id":"2","categories":["Blue Square"]},{"name":"Sheff Utd","id":"2","categories":["Prem League"]}];

const result = getTeamOptions('Prem League')(teams);

console.log(result);


8 commentaires

deux boucles coûte cher, peut-être que le transducteur est une bonne idée


@PramendraGupta: Le savez-vous? L'avez-vous testé? "L'optimisation prématurée est la racine de tout Mal". N'oubliez pas que les transducteurs ont leurs propres problèmes de performances dans JS.


@ScottSauyet J'ai pensé que le but de transduire ? est un Traitement efficace des données !


Il s'agit de la combinaison classique de filtres et de cartes. Il est lisible et aura des performances décentes, à moins que vous n'ayez d'énormes tableaux. Si vous avez d'énormes baies et que vous avez besoin de chaque once de performances, j'utiliserais une simple boucle for, et je pousserais vers une matrice pour réduire la surcharge de toute façon. Avoir un marteau ne veut pas dire que tout est un clou.


@PramendraGupta: Ils sont conçus pour améliorer les performances. Mais ils ont tendance à ne réussir à le faire dans JS que lorsque les ensembles de données sont énormes en raison de leur propre surcharge. Je suis l'un des fondateurs de Ramda, et bien que je sois impressionné par eux, je préférerais maintenant que nous ne les incluions jamais. Je ne pense pas qu'ils valent le poids supplémentaire dans la bibliothèque. Je suggérerais que pour ce problème, une implémentation de filterMap serait plus simple et plus efficace que les transducteurs.


... et si c'est utile, un filterMap est assez simple: const filterMap = (f, m) => (xs) => xs .flatMap ((x) => f ( x)? [m (x)]: []) (non testé.)


@ScottSauyet je vois que vous postez la fonction filterMap dans plusieurs réponses SO et pourtant elle ne fait pas partie de Ramda. :(


@Timar: N'hésitez pas à faire une pull request pour un. Cela pourrait valoir la peine d'être inclus. Mais il y a beaucoup de choses que j'utilise régulièrement que je n'essaye pas d'inclure dans Ramda.



0
votes
const premLeague = R.equals('Prem League');
const premLeagueInArray = R.any(premLeague);
const categories = R.path(['categories']);
const isPremLeagueInArray = R.pipe(
  categories,
  premLeagueInArray,
);

const teams = [
  { name: "Liverpool", id: "1", categories: ["Prem League"] },
  { name: "Man Utd", id: "2", categories: ["Blue Square"] },
  { name: "Sheff Utd", id: "2", categories: ["Prem League"] },
];
const premLeagueTeam = [
  { name: "Liverpool", id: "1", categories: ["Prem League"] },
  { name: "Sheff Utd", id: "2", categories: ["Prem League"] },
];

const transducer = R.compose(R.filter(isPremLeagueInArray));
const getPremLeagueTeam = R.transduce(transducer, R.flip(R.append), []);

R.equals(getPremLeagueTeam(teams), premLeagueTeam);

2 commentaires

Y a-t-il une bonne raison de croire que "Premier League" sera la première entrée du tableau? En outre, cela ne résout que la moitié du problème.


@ScottSauyet remanié pour prendre en charge n'importe quelle position.



0
votes

Vous devriez également envisager une option non-Ramda.

Cela peut ou non être un abus de Array # flatMap mais je trouve cela acceptable: filter + map = flatMap

Disons que vous voulez ajouter 10 aux nombres pairs et exclure les nombres impairs:

const getTeamOptions =
  teams =>
    teams.reduce
      ( (acc, {name: label, id: value, categories}) =>
          categories.includes('Prem League')
            ? (acc.push({ label, value }), acc)
            : acc
      , []
      );

Il y a aussi un point à faire sur le style sans point. C'est bien, mais parfois ça gêne. Par exemple, cela ne vous permet pas de tirer parti de quelques belles constructions ES6. Par exemple de déstructuration:

const getTeamOptions =
  teams =>
    teams.flatMap
      ( ({name: label, id: value, categories}) =>
          categories.includes('Prem League')
            ? { label, value }
            : []
      );

getTeamOptions
  ( [ {name: 'Liverpool', id: '1', categories: ['Prem League']}
    , {name: 'Man Utd', id: '2', categories: ['Blue Square']}
    , {name: 'Sheff Utd', id: '2', categories: ['Prem League']}
    ]
  );

//=> [ {label: "Liverpool", value: "1"}
//=> , {label: "Sheff Utd", value: "2"} ]

Pour être complet, voici une variante utilisant Array#reduce:

[1, 2, 3, 4].flatMap(n => n % 2 === 0 ? n + 10 : []);
//=> [12, 14]

Ne vous méprenez pas! Ramda est absolument incroyable . Quand j'ai rencontré cette bibliothèque pour la première fois, je voulais réécrire tout mon code avec, puis j'ai découvert le style sans point et tout réécrit. En fin de compte, j'ai complètement perdu le contrôle mental de mon code et c'est un problème. Vous ne devriez utiliser Ramda que s'il vous sert bien. Dans ce cas, vous pourriez vous en passer pour être honnête.


0 commentaires

1
votes

cela vous aiderait également à le résoudre avec ramda sans point ...

<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
const hasPremLeague = R.where({ categories: R.includes('Prem League') });
const toOption = R.applySpec({ label: R.prop('name'), value: R.prop('id') });

const getTeamOptions = R.into([], R.compose(
  R.filter(hasPremLeague), 
  R.map(toOption),
));

// ---

const teams = [
  {name: 'Liverpool', id: '1', categories: ['Prem League']},
  {name: 'Man Utd', id: '2', categories: ['Blue Square']},
  {name: 'Sheff Utd', id: '2', categories: ['Prem League']},
];

console.log(
  getTeamOptions(teams),
);


0 commentaires

0
votes

J'adore faire cela de manière composable, mais actuellement vous utilisez pipe donc je le fais avec pipe pour la cohérence. Vous trouverez ci-dessous une solution efficace

<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script>const { pipe, map, filter, prop, includes, zipObj, props } = R</script>
const teams = [
  { name: 'Liverpool', id: '1', categories: ['Prem League'] },
  { name: 'Man Utd', id: '2', categories: ['Blue Square'] },
  { name: 'Sheff Utd', id: '2', categories: ['Prem League'] }
]

const getTeamOptions = pipe(
  filter(
    pipe(
      prop('categories'),
      includes('Prem League')
    )
  ),
  map(
    pipe(
      props(['name', 'id']),
      zipObj(['label', 'value'])
    )
  )
)

console.log(getTeamOptions(teams))


0 commentaires