0
votes

Interaction profonde avec break and catch

J'ai un peu de mal à écrire un scénario.

J'ai une structure de cours qui se compose de plusieurs modules, et chaque module peut avoir plusieurs leçons.

Lorsque l'utilisateur entre sur la page, il doit être défini quelle leçon sera sélectionnée pour lui.

La règle de gestion est la suivante: sélectionnez la première leçon qui n'a pas été consultée et le module auquel appartient cette leçon. S'ils sont tous affichés, sélectionnez la première leçon de la première leçon.

course.modules.find((module) => {
  return module.lessons.find((lesson) => {
    if (!lesson.viewed) {
      selectedModule = module
      selectedLesson = lesson

      return true
    } else {
      return false
    }
  })
})

j'ai essayé quelque chose comme

const course = {
  title: 'Course name',
  duration: '1h 30min',
  modules: [
    {
      title: 'first module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: true
        }
      ]
    },
    {
      title: 'second module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    },
    {
      title: 'third module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: false
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    }
  ]
}

const selectedModule = {}
const selectedLesson = {}

mais cela ne semble pas être une bonne solution, à part que je ne fais pas de catch si la find échoue, puis sélectionnez la première leçon, à partir du premier module.

Que puis-je essayer ensuite?


12 commentaires

parcourez votre objet de manière récursive et renvoyez la leçon si elle répond à vos critères ou appelez la suivante si elle ne le fait pas


Je ne comprends pas ce que tout cela a à voir avec la pause ou la capture?


find renvoie un objet, ne l'utilisez pas pour définir des propriétés telles que selectedModule . Rends-les simplement


@Liam si vous trouvez la leçon qui correspond aux critères, devrait s'arrêter. si non trouvé, entrez catch


Quel est le problème avec la simple utilisation d'une instruction if ? Ce que vous essayez de faire ici est vraiment très peu clair.


Vous ne devriez pas définir de variables à l'intérieur de find. Une boucle for avec find aurait en fait plus de sens que deux trouvailles imbriquées.


@Liam select the first lesson that has not been viewed, and the module to which that lesson belongs. If they are all vieweds, select the first lesson of the first lesson. n'est-ce pas assez clair? désolé si j'ai du mal à l'obtenir, si c'était clair pour moi, je ne serais pas venu demander de l'aide


@epascarello pouvez-vous montrer un exemple de ce que cela pourrait être?


@YungSilva Il y a beaucoup de réponses trop complexes à mon avis. Je pense que le moyen le plus propre de résoudre votre problème est d' utiliser un réducteur


@Ollie Reduce fait plus d'itérations que nécessaire. Cela fait un travail supplémentaire.


@epascarello Vous avez raison, mais dans cet exemple, je pense qu'un code plus propre serait de loin préférable à de minuscules améliorations de performances.


C'est l'opinion personnelle qui est un code plus propre. Pour moi, le code qui sort quand il trouve la bonne chose est plus propre. Ce serait une simple boucle. Le code d'OP fonctionne également et sort, personnellement ce n'est pas "propre" puisque ce n'est généralement pas ainsi que fonctionne find (), mais le code est efficace et sort.


6 Réponses :


0
votes

Essayez quelque chose comme ça

var module_and_lesson_loaded = 
  (course.modules.length>0 & course.modules.find((module))?
  course.modules.find((module) => {
   return (module.lessons.length>0 && module.lessons.find((lesson))?
    module.lessons.find((lesson) => {
    if (!lesson.viewed) {
      selectedModule = module
      selectedLesson = lesson

      return true
    } else {
      return false
    }
  }):false;
}):false;

 if(module_and_lesson_loaded){
   //your code here
 }else{
   selectedModule = course.modules[0]
   selectedLesson = selectedModule.lessons[0]
 }

Eh bien, ce n'est peut-être pas la bonne façon, je suppose, mais cela vérifiera si ces tableaux ne sont pas vides et renverra un null s'ils le sont.


0 commentaires

1
votes

Je ferais de cette façon:

  • Trouvez le premier module incomplet, c'est-à-dire le module avec au moins une leçon non vue.

  • Obtenez la leçon non vue du module correspondant.

  • Si tous sont consultés, trouvez le premier module avec au moins une leçon, obtenez la première leçon .

{title: "first module", lessons: Array(2)}
{title: "lesson 1", viewed: true}

Sortie pour vos exemples de données:

{title: "second module", lessons: Array(2)}
{title: "lesson 2", viewed: false}

Quand tout est réglé sur vu: vrai

let x, y;
const incompleteModule = course.modules.find(module => module.lessons & module.lessons.length && module.lessons.some(({viewed}) => !viewed));

if (incompleteModule) {
    x = incompleteModule; 
    y = incompleteModule.lessons.find(({viewed}) => !viewed); 
} else {
    x = course.modules.find(module => module.lessons.length);
    y = x.lessons[0];
}


5 commentaires

Vous devez exécuter votre code. Ce sera une erreur.


Non, vous avez un problème de logique. Vous en avez utilisé là où il ne devrait pas y en avoir


Rendez votre code exécutable, vous verrez votre problème.


"incompletModule" est un booléen dans votre code. En l' "Uncaught TypeError: Cannot read property 'find' of undefined", vous aurez "Uncaught TypeError: Cannot read property 'find' of undefined",


Merci @epascarello, je l'ai corrigé.



1
votes

Votre solution pourrait fonctionner, mais ce n'est pas la meilleure chose à faire. Il vous suffit de définir les paramètres par défaut au début.

 const course = {
  title: 'Course name',
  duration: '1h 30min',
  modules: [
    {
      title: 'first module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: true
        }
      ]
    },
    {
      title: 'second module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    },
    {
      title: 'third module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: false
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    }
  ]
}


// set the default to first module and lesson
let selectedModule = course.modules[0];
let selectedLesson = selectedModule.lessons[0];

// loop over modules
for (const module of course.modules) {
  // look for lesson not viewed
  const unviewedLession = module.lessons.find(lesson => !lesson.viewed)
  // if new lesson, use that and exit
  if (unviewedLession) {
    selectedModule = module;
    selectedLesson = unviewedLession;
    break;
  }
}

console.log(selectedModule.title, selectedLesson.title);

Dans votre code, vous essayez d'en faire trop à la fois. Vous devez le diviser en une boucle for que vous pouvez quitter et une recherche qui recherchera les leçons non vues. Vous avez eu la bonne idée, n'utilisez pas find () pour définir des variables.

const course = {
  title: 'Course name',
  duration: '1h 30min',
  modules: [{
      title: 'first module',
      lessons: [{
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: true
        }
      ]
    },
    {
      title: 'second module',
      lessons: [{
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    },
    {
      title: 'third module',
      lessons: [{
          title: 'lesson 1',
          viewed: false
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    }
  ]
}

let selectedModule = course.modules[0]
let selectedLesson = selectedModule.lessons[0]

course.modules.find((module) => {
  return module.lessons.find((lesson) => {
    if (!lesson.viewed) {
      selectedModule = module
      selectedLesson = lesson

      return true
    } else {
      return false
    }
  })
})

console.log(selectedModule.title, selectedLesson.title);


0 commentaires

0
votes

Compte tenu de votre règle commerciale:

sélectionnez la première leçon qui n'a pas été consultée et le module auquel appartient cette leçon. S'ils sont tous affichés, sélectionnez la première leçon de la première leçon.

Un réducteur fonctionne parfaitement ici:

// Loop through all modules and perform logic to determine the result
const result = course.modules.reduce((firstUnviewedLesson, currentModule) => {
  // If we already found the first unviewed lesson, return it
  if (firstUnviewedLesson) return firstUnviewedLesson
  
  // Attempt to find an unviewed lesson within the module
  const unviewedLesson = currentModule.lessons.find(lesson => lesson.viewed === false)

  // If it is found, create our custom object stating the module name and the title of the lesson
  if (unviewedLesson) {
    console.log('Found unviewed lesson')
    return {
      moduleTitle: currentModule.title,
      unviewedLesson: unviewedLesson.title
    }
  }
}, null)

Après avoir exécuté cette logique, vous pouvez vérifier si result === null - dans ce cas, cela signifie que toutes les leçons ont été visualisées et que vous pouvez effectuer la deuxième partie de votre logique métier.


0 commentaires

0
votes

const course = {
  title: 'Course name',
  duration: '1h 30min',
  modules: [
    {
      title: 'first module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: true
        }
      ]
    },
    {
      title: 'second module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: true
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    },
    {
      title: 'third module',
      lessons: [
        {
          title: 'lesson 1',
          viewed: false
        },
        {
          title: 'lesson 2',
          viewed: false
        }
      ]
    }
  ]
}

const isEmpty = obj => {
    return (Object.keys(obj).length === 0 & obj.constructor === Object);
    }

const findLesson = course => {
  let selected = {};
  course.modules.every(module => {
    if(!isEmpty(selected)) return;
    module.lessons.every(lesson => {
      if (lesson.viewed === false) {
        selected = {module: module.title, lesson: lesson.title};
        return;
      }
    });
  });
  return (isEmpty(selected)) ? {lesson: "lesson1", module: "first module"} : selected;
};

console.log(findLesson(course));


2 commentaires

Il est propre, la seule critique est qu'il boucle plus de fois que nécessaire, car il n'est pas facile de quitter forEach. MAIS il sélectionne le mauvais module / leçon puisque vous continuez à vérifier.


vous avez raison, je l'ai retravaillé pour utiliser .every au lieu de forEach



0
votes

L'approche suivante utilise intentionnellement deux fois Array.prototype.some . Il s'agit donc probablement de la seule approche basée sur des méthodes matricielles qui itère le moins d'étapes possibles. Il quitte immédiatement les deux conditions en même temps, dès que la première leçon non visitée a été trouvée.

Les informations du module sont recueillies au moyen d' un objet qui se transmet comme this contexte des deux méthodes de rappel ...

.as-console-wrapper { min-height: 100%!important; top: 0; }
const course = {
  title: 'Course name',
  duration: '1h 30min',
  modules: [{
    title: 'first module',
    lessons: [{
      title: 'lesson 1',
      viewed: true
    }, {
      title: 'lesson 2',
      viewed: true
    }]
  }, {
    title: 'second module',
    lessons: [{
      title: 'lesson 1',
      viewed: true
    }, {
      title: 'lesson 2',
      viewed: false
    }]
  }, {
    title: 'third module',
    lessons: [{
      title: 'lesson 1',
      viewed: false
    }, {
      title: 'lesson 2',
      viewed: false
    }]
  }]
};


function assignModuleData(data, module, idx) {
  data.moduleTitle = module.title;
  data.moduleIdx = idx;
  data.module = module;
}
function assignLessonData(data, lesson, idx) {
  data.lessonTitle = lesson.title;    
  data.lessonIdx = idx;
  data.lesson = lesson;
}
function assignDefaultLesson(data, modules) {
  assignModuleData(data, modules[0], 0)
  assignLessonData(data, modules[0].lessons[0], 0)
}

function isUnviewedLessonAndWhichIsIt(lesson, idx) {
  const data = this;
  const isUnviewedLesson = !lesson.viewed;

  if (isUnviewedLesson) {
    assignLessonData(data, lesson, idx)
  }
  return isUnviewedLesson;
}
function isModuleWithUnviewedLessonAndWhichIsIt(module, idx, arr) {
  const data = this;

  assignModuleData(data, module, idx);
  const isModuleWithUnviewedLesson = module.lessons.some(isUnviewedLessonAndWhichIsIt, data);

  if ((idx >= (arr.length - 1)) & !isModuleWithUnviewedLesson) {
    assignDefaultLesson(data, arr);
  }
  return isModuleWithUnviewedLesson;
}


const nextLesson = {}

course.modules.some(isModuleWithUnviewedLessonAndWhichIsIt, nextLesson);

console.log(`"${ nextLesson.moduleTitle }, ${ nextLesson.lessonTitle }"`);
console.log(' nextLesson :', nextLesson);


0 commentaires