Ok le titre est très général mais je pense qu'il me manque les mots pour l'expliquer correctement.

Je récupère donc des données à partir d'une API externe et je souhaite filtrer certains des résultats. J'utilise un forEach pour parcourir la réponse et ensuite une instruction if pour en exclure certains en fonction de certains critères.

Dans ce cas, je récupère des données de film et je souhaite exclure les films qui reviennent sans URL img. Cette partie fonctionne bien. Ensuite, je veux exclure les films qui ont un faible niveau de popularité. Le niveau de popularité de l'objet json est défini par un nombre sous la forme de 4,45644.

const findMovies = response.results;
  findMovies.forEach( movie => {
    if (movie.poster_path != null && movie.popularity > 8) {
       // print to DOM
    } else {
      //dont print nothing
    }

Le problème est qu'avec le code ci-dessus, je filtre tous les films qui ont une popularité plus petite OU plus grande que 8. Je suis sûr qu'il me manque quelque chose de vraiment stupide mais j'ai passé quelques heures coincé jusqu'à présent.

Faites-moi savoir si vous avez besoin d'autres extraits de code qui pourraient être utiles.

C'est essentiellement ce que la réponse de l'API enregistre sur la console

results: Array(20)
  0:
    adult:false
    poster_path: "/tjQHn6xW5BiB1RJ3OZIPDzIOSkF.jpg"
    popularity: 30.400022
    ....
1
grenos 13 avril 2018 à 21:51

3 réponses

Meilleure réponse

Voici un code que nous pouvons examiner. Je veux oublier votre code existant et aller au fond du problème qui est de tirer une liste de films et de les analyser et de les trier de manière personnalisée.

J'ai choisi d'utiliser Array.reduce() car cela nous permet de parcourir chaque film provenant de votre base de données et de l'analyser pour ce que nous ressentons, puis il crée un objet de sortie qui filtre les résultats correspondants et maintient une liste de films rejetés.

Je l'ai fait parce que je veux que vous sachiez comment reduce fonctionne (parce que c'est génial)

// Simulate the Movie DB
const movies = [
  { title: 'Sammy goes to the store', poster_path: 'http://www.com/photo.jpg', popularity: 2, url: 'http://www.com' },
  { title: 'Sammy doesnt go to the store', poster_path: 'http://www.com/photo.jpg', popularity: 4, url: '' },
  { title: 'Willy goes to Whalemart', poster_path: 'http://www.com/photo.jpg', popularity: 6, url: 'http://www.com' },
  { title: 'Jimmy only had one job', poster_path: 'http://www.com/photo.jpg', popularity: 8, url: '' },
  { title: 'Jimmy no longer has one job', poster_path: 'http://www.com/photo.jpg', popularity: 10, url: 'http://www.com' },
  { title: 'Fred goes to the farm', poster_path: undefined, popularity: 12, url: 'http://www.com' },
  { title: 'Fred doesnt go to the farm', poster_path: 'http://www.com/photo.jpg', popularity: 14, url: '' },
  { title: 'Helga goes to the hackathon', poster_path: 'http://www.com/photo.jpg', popularity: 16, url: 'http://www.com' },
  { title: 'Bhima only had one job', poster_path: 'http://www.com/photo.jpg', popularity: 18, url: '' },
  { title: 'Bhima no longer has one job', poster_path: null, popularity: 20, url: 'http://www.com' },
]

// Simulate the network request to get the movies
const response = { results: movies }

// Start with your existing code
const findMovies = response.results

// Rather than forEach, we will use Array.map() or Array.reduce()
// and set the filtered results into a new Array,
// because it provides you more utility overall
const filteredMovies = findMovies.reduce((acc, movie) => {
  if (movie.poster_path == null) {
    // console.log('REJECTING:', movie, 'REASON: no photo')
    movie.rejectReason = 'no photo'
    acc.rejects.push(movie)
    return acc
  }
  if (movie.popularity < 8) {
    // console.log('REJECTING:', movie, 'REASON: bad rating')
    movie.rejectReason = 'bad rating'
    acc.rejects.push(movie)
    return acc
  }
  acc.matches.push(movie)
  return acc
}, { matches: [], rejects: [] })

console.log('MATCHES', filteredMovies.matches)

console.log('\nREJECTS', filteredMovies.rejects)

Tout d'abord, Array.map() ou Array.reduce() sont très similaires à Array.forEach(). Si vous le savez déjà, incroyable - je vous aime. Tous les trois franchissent un itérable et font quelque chose avec chaque élément. La différence est que la carte produit un nouveau tableau et la réduction peut produire n'importe quelle structure de données. Cela rend le processus immuable et une bonne pratique. Vous devrez rechercher l'immuabilité par vous-même. Si vous le faites, faites attention à la façon dont JavaScript conserve les références en direct aux non primitifs. Cela peut créer des cauchemars lorsqu'un «état mutable partagé» est impliqué.

Deuxièmement, Array.reduce() est un peu plus que la carte car c'est un accumulateur. Si vous n'êtes pas familier, je vous recommande vivement de tout savoir sur la réduction. Pour faire court, dans mon exemple, nous accumulons un objet qui a deux clés: matches et rejects. Nous enjambons chaque élément du film Array et l'analysons avec votre logique d'origine, mais je l'ai inversé à l'inverse de ce que vous aviez. Ça va comme ça:

1) Examiner chaque film

2) Si movie.poster_path == null: le film est un rejet, poussez-le dans le tableau de rejet que nous accumulons. L'utilisation de == interceptera toutes les valeurs de falsification, telles que '', 0, undefined et null.

3) Si movie.popularity < 8: le film est un rejet, poussez-le dans le tableau de rejet que nous accumulons.

4) Avant de passer au film suivant de la liste, nous ajoutons une propriété rejectReason au résultat du film (juste au cas où nous voudrions l'examiner plus tard ou l'afficher dans un message d'erreur).

5) Remarquez comment la fonction de réduction est une liste d'instructions if qui provoquent un rejet, et la dernière étape indique: "Si le film n'a pas encore été rejeté, ajoutez-le au tableau matches que nous accumulons.

Note bonus : acc signifie accumulateur. Si vous regardez de près, nous accumulons quelque chose pendant que la fonction de réduction fait une boucle sur chaque élément. Quand il dit return acc. Cela signifie, renvoyez l'accumulateur afin que le prochain élément puisse également l'utiliser.

Puisque vous avez consacré beaucoup de temps à ce problème, je voulais vous aider à comprendre comment penser à faire ce type de "transformation d'une liste en un ensemble filtré". J'utilise et préconise des techniques de programmation fonctionnelles. cartographier, filtrer et réduire sont au cœur de cette façon de penser, tout comme les structures de données immuables et généralement le flux de données à sens unique. Notez ces mots clés que je laisse tomber et faites toujours attention lorsque les gens en parlent. Ces choses deviendront de plus en plus attrayantes pour vous au fur et à mesure que vous gérerez des événements asynchrones plus fous dans des applications complexes.

3
agm1984 13 avril 2018 à 20:05

Vous pouvez également essayer:

const result = findMovies.filter(movies => movies.popularity > 8);
console.log(result);

Cela filtrera le tableau avec le résultat final de renvoyer uniquement les films avec une popularité supérieure à 8. Vous pouvez ensuite utiliser .forEach () à la fin de cela également pour parcourir ce résultat si vous ne recherchez que certaines valeurs de la clés etc

0
Bruce O. 13 avril 2018 à 21:12

Essaye ça

  const findMovies = response.results;
    findMovies.forEach( movie => {
      if (movie.poster_path != null && (8-movie.popularity> 0d)){
         // print to DOM
      } else {
         //dont print anything
      }
1
honey92 13 avril 2018 à 19:48