feat(quiz): initial quiz view which can be used for multiple choice (#15743)
quizes
This commit is contained in:
committed by
Quincy Larson
parent
93148665c6
commit
9f875e1d11
@ -10,6 +10,7 @@ import Classic from './views/classic';
|
||||
import Step from './views/step';
|
||||
import Project from './views/project';
|
||||
import BackEnd from './views/backend';
|
||||
import Quiz from './views/quiz';
|
||||
|
||||
import { challengeMetaSelector } from './redux';
|
||||
import {
|
||||
@ -27,7 +28,8 @@ const views = {
|
||||
classic: Classic,
|
||||
project: Project,
|
||||
simple: Project,
|
||||
step: Step
|
||||
step: Step,
|
||||
quiz: Quiz
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
@ -3,13 +3,15 @@ import { panesMap as backendPanesMap } from './views/backend';
|
||||
import { panesMap as classicPanesMap } from './views/classic';
|
||||
import { panesMap as stepPanesMap } from './views/step';
|
||||
import { panesMap as projectPanesMap } from './views/project';
|
||||
import { panesMap as quizPanesMap } from './views/quiz';
|
||||
|
||||
export function createPanesMap() {
|
||||
return {
|
||||
...backendPanesMap,
|
||||
...classicPanesMap,
|
||||
...stepPanesMap,
|
||||
...projectPanesMap
|
||||
...projectPanesMap,
|
||||
...quizPanesMap
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@ const submitters = {
|
||||
backend: submitBackendChallenge,
|
||||
step: submitSimpleChallenge,
|
||||
video: submitSimpleChallenge,
|
||||
quiz: submitSimpleChallenge,
|
||||
'project.frontEnd': submitProject,
|
||||
'project.backEnd': submitProject,
|
||||
'project.simple': submitSimpleChallenge
|
||||
|
@ -27,6 +27,7 @@ import { bonfire, html, js } from '../../../utils/challengeTypes';
|
||||
import blockNameify from '../../../utils/blockNameify';
|
||||
import { createPoly, setContent } from '../../../../utils/polyvinyl';
|
||||
import createStepReducer, { epics as stepEpics } from '../views/step/redux';
|
||||
import createQuizReducer from '../views/quiz/redux';
|
||||
import createProjectReducer from '../views/project/redux';
|
||||
|
||||
// this is not great but is ok until we move to a different form type
|
||||
@ -361,6 +362,7 @@ export default function createReducers() {
|
||||
return [
|
||||
reducer,
|
||||
...createStepReducer(),
|
||||
...createProjectReducer()
|
||||
...createProjectReducer(),
|
||||
...createQuizReducer()
|
||||
];
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ export const viewTypes = {
|
||||
// formally hikes
|
||||
[ challengeTypes.video ]: 'video',
|
||||
[ challengeTypes.step ]: 'step',
|
||||
[ challengeTypes.quiz ]: 'quiz',
|
||||
backend: 'backend'
|
||||
};
|
||||
|
||||
@ -34,6 +35,7 @@ export const submitTypes = {
|
||||
// formally hikes
|
||||
[ challengeTypes.video ]: 'video',
|
||||
[ challengeTypes.step ]: 'step',
|
||||
[ challengeTypes.quiz ]: 'quiz',
|
||||
backend: 'backend'
|
||||
};
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
&{ @import "./classic/classic.less"; }
|
||||
&{ @import "./step/step.less"; }
|
||||
&{ @import "./quiz/quiz.less"; }
|
||||
|
@ -2,12 +2,11 @@ import React from 'react';
|
||||
|
||||
import Main from './Project.jsx';
|
||||
import { types } from '../../redux';
|
||||
import Panes from '../../../../Panes';
|
||||
import _Map from '../../../../Map';
|
||||
import ChildContainer from '../../../../Child-Container.jsx';
|
||||
import Panes from '../../../../Panes';
|
||||
|
||||
const propTypes = {};
|
||||
|
||||
export const panesMap = {
|
||||
[types.toggleMap]: 'Map',
|
||||
[types.toggleMain]: 'Main'
|
||||
|
82
common/app/routes/challenges/views/quiz/Choice.jsx
Normal file
82
common/app/routes/challenges/views/quiz/Choice.jsx
Normal file
@ -0,0 +1,82 @@
|
||||
import React, { PropTypes, PureComponent } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import classnames from 'classnames';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import {
|
||||
selectChoice,
|
||||
incrementCorrect
|
||||
} from './redux';
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
() => ({})
|
||||
);
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return () => bindActionCreators({
|
||||
selectChoice,
|
||||
incrementCorrect
|
||||
}, dispatch);
|
||||
}
|
||||
|
||||
const propTypes = {
|
||||
choice: PropTypes.string,
|
||||
choiceIndex: PropTypes.number,
|
||||
incrementCorrect: PropTypes.func,
|
||||
isChoiceSelected: PropTypes.bool,
|
||||
isCorrectChoice: PropTypes.bool,
|
||||
selectChoice: PropTypes.func,
|
||||
selected: PropTypes.bool
|
||||
};
|
||||
|
||||
export class Choice extends PureComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.selectChoice = this.selectChoice.bind(this);
|
||||
}
|
||||
|
||||
selectChoice() {
|
||||
if (this.props.isChoiceSelected) {
|
||||
return;
|
||||
}
|
||||
if (this.props.isCorrectChoice) {
|
||||
this.props.incrementCorrect();
|
||||
}
|
||||
this.props.selectChoice(this.props.choiceIndex);
|
||||
}
|
||||
|
||||
render() {
|
||||
const choiceClass = classnames({
|
||||
choice: true,
|
||||
selected: this.props.selected,
|
||||
correct: this.props.isCorrectChoice,
|
||||
reveal: this.props.isChoiceSelected
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={choiceClass}
|
||||
onClick={this.selectChoice}
|
||||
>
|
||||
<div className='radio'>
|
||||
<div className='inside' />
|
||||
</div>
|
||||
|
||||
<div
|
||||
className='text'
|
||||
dangerouslySetInnerHTML={{__html: this.props.choice}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Choice.displayName = 'Choice';
|
||||
Choice.propTypes = propTypes;
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Choice);
|
222
common/app/routes/challenges/views/quiz/Quiz.jsx
Normal file
222
common/app/routes/challenges/views/quiz/Quiz.jsx
Normal file
@ -0,0 +1,222 @@
|
||||
import React, { PropTypes, PureComponent } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { Col, Row } from 'react-bootstrap';
|
||||
import Choice from './Choice.jsx';
|
||||
|
||||
import {
|
||||
currentIndexSelector,
|
||||
selectedChoiceSelector,
|
||||
nextQuestion,
|
||||
selectChoice,
|
||||
correctSelector,
|
||||
incrementCorrect,
|
||||
resetQuiz,
|
||||
resetChoice
|
||||
} from './redux';
|
||||
|
||||
import { submitChallenge, challengeMetaSelector } from '../../redux';
|
||||
import { challengeSelector } from '../../../../redux';
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
challengeSelector,
|
||||
challengeMetaSelector,
|
||||
currentIndexSelector,
|
||||
selectedChoiceSelector,
|
||||
correctSelector,
|
||||
(
|
||||
{
|
||||
description = [],
|
||||
title
|
||||
},
|
||||
meta,
|
||||
currentIndex,
|
||||
selectedChoice,
|
||||
correct
|
||||
) => ({
|
||||
title,
|
||||
description,
|
||||
meta,
|
||||
currentIndex,
|
||||
selectedChoice,
|
||||
correct
|
||||
})
|
||||
);
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return () => bindActionCreators({
|
||||
nextQuestion,
|
||||
selectChoice,
|
||||
incrementCorrect,
|
||||
resetQuiz,
|
||||
resetChoice,
|
||||
submitChallenge
|
||||
}, dispatch);
|
||||
}
|
||||
|
||||
const propTypes = {
|
||||
correct: PropTypes.number,
|
||||
currentIndex: PropTypes.number,
|
||||
description: PropTypes.string,
|
||||
meta: PropTypes.object,
|
||||
nextQuestion: PropTypes.fun,
|
||||
resetChoice: PropTypes.fun,
|
||||
resetQuiz: PropTypes.fun,
|
||||
selectedChoice: PropTypes.number,
|
||||
submitChallenge: PropTypes.fun
|
||||
};
|
||||
|
||||
export class QuizChallenge extends PureComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.nextQuestion = this.nextQuestion.bind(this);
|
||||
this.submitChallenge = this.submitChallenge.bind(this);
|
||||
}
|
||||
|
||||
nextQuestion() {
|
||||
this.props.resetChoice();
|
||||
this.props.nextQuestion();
|
||||
}
|
||||
|
||||
submitChallenge() {
|
||||
this.props.resetQuiz();
|
||||
this.props.submitChallenge();
|
||||
}
|
||||
|
||||
renderTitle() {
|
||||
return (
|
||||
<Row className='quizTitle'>
|
||||
<Col md={12}>
|
||||
<h4>{this.props.meta.title}</h4>
|
||||
<hr/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
renderResults() {
|
||||
const isQuizPassed = this.props.correct === this.props.description.length;
|
||||
return (
|
||||
<div>
|
||||
{this.renderTitle()}
|
||||
<Row className='quizResults'>
|
||||
<Col md={12}>
|
||||
<h2>Quiz Results:</h2>
|
||||
|
||||
<p>
|
||||
You got {this.props.correct} out of
|
||||
{this.props.description.length} correct!
|
||||
</p>
|
||||
|
||||
{isQuizPassed === false ? (
|
||||
<div>
|
||||
<p>
|
||||
You will need to get all the questions
|
||||
correct in order to mark this quiz as completed.
|
||||
</p>
|
||||
<button
|
||||
className='btn btn-lg btn-primary'
|
||||
onClick={this.props.resetQuiz}
|
||||
> Try Again
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className='btn btn-lg btn-primary'
|
||||
onClick={this.submitChallenge}
|
||||
> Finish Quiz
|
||||
</button>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderQuiz() {
|
||||
const currentIndex = this.props.currentIndex;
|
||||
const question = this.props.description[currentIndex];
|
||||
return (
|
||||
<div>
|
||||
{this.renderTitle()}
|
||||
<Row>
|
||||
<Col md={6}>
|
||||
<h2 className='textCenter'>
|
||||
Question {currentIndex + 1} of {this.props.description.length}:
|
||||
</h2>
|
||||
|
||||
<h3>
|
||||
{question.subtitle}:
|
||||
</h3>
|
||||
|
||||
<p dangerouslySetInnerHTML={{__html: question.question}} />
|
||||
</Col>
|
||||
|
||||
<Col md={6}>
|
||||
<h2 className='textCenter'>Choices</h2>
|
||||
|
||||
{question.choices.map((choice, i) => (
|
||||
<Choice
|
||||
choice={choice}
|
||||
choiceIndex={i}
|
||||
isChoiceSelected={this.props.selectedChoice !== null}
|
||||
isCorrectChoice={question.answer === i}
|
||||
key={choice}
|
||||
selected={i === this.props.selectedChoice}
|
||||
/>
|
||||
))}
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{this.props.selectedChoice !== null &&
|
||||
<Row className='quizResults'>
|
||||
<Col md={6} mdPush={3}>
|
||||
<div className='messageDiv'>
|
||||
{this.props.selectedChoice === question.answer
|
||||
? <h2 className='correctAnswer'>
|
||||
Correct, great work!
|
||||
</h2>
|
||||
: <h2 className='wrongAnswer'>
|
||||
Sorry, that is not correct!
|
||||
</h2>}
|
||||
</div>
|
||||
{this.props.selectedChoice !== question.answer &&
|
||||
<div className='explanation'>
|
||||
<h2>Explanation:</h2>
|
||||
<p dangerouslySetInnerHTML={{__html: question.explanation}} />
|
||||
</div>}
|
||||
</Col>
|
||||
|
||||
<Col md={12}>
|
||||
<button
|
||||
className='btn btn-lg btn-primary'
|
||||
onClick={this.nextQuestion}
|
||||
>
|
||||
{currentIndex + 1 === this.props.description.length ?
|
||||
'View Results' : 'Next Question'}
|
||||
</button>
|
||||
</Col>
|
||||
</Row>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='quiz'>{
|
||||
this.props.currentIndex >= this.props.description.length ?
|
||||
this.renderResults() : this.renderQuiz()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QuizChallenge.displayName = 'QuizChallenge';
|
||||
QuizChallenge.propTypes = propTypes;
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(QuizChallenge);
|
33
common/app/routes/challenges/views/quiz/Show.jsx
Normal file
33
common/app/routes/challenges/views/quiz/Show.jsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
|
||||
import Main from './Quiz.jsx';
|
||||
import { types } from '../../redux';
|
||||
import Panes from '../../../../Panes';
|
||||
import _Map from '../../../../Map';
|
||||
import ChildContainer from '../../../../Child-Container.jsx';
|
||||
|
||||
const propTypes = {};
|
||||
export const panesMap = {
|
||||
[types.toggleMap]: 'Map',
|
||||
[types.toggleMain]: 'Main'
|
||||
};
|
||||
|
||||
const nameToComponent = {
|
||||
Map: {
|
||||
Component: _Map
|
||||
},
|
||||
Main: {
|
||||
Component: Main
|
||||
}
|
||||
};
|
||||
|
||||
export default function ShowQuiz() {
|
||||
return (
|
||||
<ChildContainer isFullWidth={ true }>
|
||||
<Panes nameToComponent={ nameToComponent }/>
|
||||
</ChildContainer>
|
||||
);
|
||||
}
|
||||
|
||||
ShowQuiz.displayName = 'ShowQuiz';
|
||||
ShowQuiz.propTypes = propTypes;
|
1
common/app/routes/challenges/views/quiz/index.js
Normal file
1
common/app/routes/challenges/views/quiz/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default, panesMap } from './Show.jsx';
|
1
common/app/routes/challenges/views/quiz/ns.json
Normal file
1
common/app/routes/challenges/views/quiz/ns.json
Normal file
@ -0,0 +1 @@
|
||||
"quiz"
|
93
common/app/routes/challenges/views/quiz/quiz.less
Normal file
93
common/app/routes/challenges/views/quiz/quiz.less
Normal file
@ -0,0 +1,93 @@
|
||||
// should match ./ns.json value and filename
|
||||
@ns: quiz;
|
||||
|
||||
.quiz {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
|
||||
.quizTitle {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.textCenter {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.explanation p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.quizResults {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrongAnswer {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.correctAnswer {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.choice.selected {
|
||||
.radio {
|
||||
.inside {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.choice:not(.reveal):hover > .radio {
|
||||
.inside {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.choice {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
|
||||
.text {
|
||||
|
||||
}
|
||||
|
||||
.radio {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 100%;
|
||||
border: 4px solid #333;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
|
||||
.inside {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
left: 2px;
|
||||
top: 2px;
|
||||
background-color: #333;
|
||||
border-radius: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.choice:not(.reveal):hover {
|
||||
background-color: rgba(0, 100, 0, 0.3);
|
||||
}
|
||||
|
||||
.choice:not(.reveal) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.choice.reveal {
|
||||
background-color: rgba(255, 65, 77, 0.3);
|
||||
}
|
||||
|
||||
.choice.reveal.correct {
|
||||
background-color: rgba(0, 100, 0, 0.3);
|
||||
}
|
||||
}
|
79
common/app/routes/challenges/views/quiz/redux/index.js
Normal file
79
common/app/routes/challenges/views/quiz/redux/index.js
Normal file
@ -0,0 +1,79 @@
|
||||
import { createTypes } from 'redux-create-types';
|
||||
import { createAction, handleActions } from 'redux-actions';
|
||||
import noop from 'lodash/noop';
|
||||
|
||||
import ns from '../ns.json';
|
||||
|
||||
export const types = createTypes([
|
||||
'nextQuestion',
|
||||
'selectChoice',
|
||||
'incrementCorrect',
|
||||
'resetQuiz',
|
||||
'resetChoice'
|
||||
], ns);
|
||||
|
||||
export const nextQuestion = createAction(
|
||||
types.nextQuestion,
|
||||
noop
|
||||
);
|
||||
|
||||
export const selectChoice = createAction(
|
||||
types.selectChoice,
|
||||
(selectedChoice) => ({ selectedChoice })
|
||||
);
|
||||
|
||||
export const incrementCorrect = createAction(
|
||||
types.incrementCorrect,
|
||||
noop
|
||||
);
|
||||
|
||||
export const resetQuiz = createAction(
|
||||
types.resetQuiz,
|
||||
noop
|
||||
);
|
||||
|
||||
export const resetChoice = createAction(
|
||||
types.resetChoice,
|
||||
noop
|
||||
);
|
||||
|
||||
const initialState = {
|
||||
currentIndex: 0,
|
||||
selectedChoice: null,
|
||||
correct: 0
|
||||
};
|
||||
|
||||
export const getNS = state => state[ns];
|
||||
export const currentIndexSelector = state => getNS(state).currentIndex;
|
||||
export const selectedChoiceSelector = state => getNS(state).selectedChoice;
|
||||
export const correctSelector = state => getNS(state).correct;
|
||||
|
||||
export default function createReducers() {
|
||||
const reducer = handleActions({
|
||||
[types.nextQuestion]: state => ({
|
||||
...state,
|
||||
currentIndex: state.currentIndex + 1
|
||||
}),
|
||||
[types.selectChoice]: (state, {payload}) => ({
|
||||
...state,
|
||||
selectedChoice: payload.selectedChoice
|
||||
}),
|
||||
[types.incrementCorrect]: state => ({
|
||||
...state,
|
||||
correct: state.correct + 1
|
||||
}),
|
||||
[types.resetQuiz]: state => ({
|
||||
...state,
|
||||
currentIndex: 0,
|
||||
correct: 0,
|
||||
selectedChoice: null
|
||||
}),
|
||||
[types.resetChoice]: state => ({
|
||||
...state,
|
||||
selectedChoice: null
|
||||
})
|
||||
}, initialState);
|
||||
|
||||
reducer.toString = () => ns;
|
||||
return [ reducer ];
|
||||
}
|
@ -9,3 +9,4 @@ export const backEndProject = 4;
|
||||
export const bonfire = 5;
|
||||
export const video = 6;
|
||||
export const step = 7;
|
||||
export const quiz = 8;
|
||||
|
@ -81,7 +81,13 @@
|
||||
""
|
||||
]
|
||||
],
|
||||
"challengeSeed": [],
|
||||
"challengeSeed": [
|
||||
"function sym(args) {",
|
||||
" return args;",
|
||||
"}",
|
||||
"",
|
||||
"sym([1, 2, 3], [5, 2, 1, 4]);"
|
||||
],
|
||||
"tests": [],
|
||||
"type": "Waypoint",
|
||||
"challengeType": 7,
|
||||
|
@ -0,0 +1,112 @@
|
||||
{
|
||||
"name": "JavaScript Multiple Choice Questions",
|
||||
"order": 8,
|
||||
"time": "",
|
||||
"helpRoom": "HelpJavaScript",
|
||||
"challenges": [
|
||||
{
|
||||
"id": "59874fc749228906236a3275",
|
||||
"title": "Array.prototype.map",
|
||||
"description": [
|
||||
{
|
||||
"subtitle": "Flooring an Array",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1.32, 2.43, 3.9]\n .map(Math.floor);\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>1.32 2.43 3.9</code></pre>",
|
||||
"<pre><code class='language-javascript'>['1.32', '2.43', '3.9']</code></pre>",
|
||||
"<pre><code class='language-javascript'>[1, 2, 3]</code></pre>",
|
||||
"<pre><code class='language-javascript'>'1 2 3'</code></pre>"
|
||||
],
|
||||
"answer": 2,
|
||||
"explanation": "The map function takes a callback function as it's first parameter and applies that function against every value inside the array. In this example, our callback function is the <code>Math.floor</code> function which will truncate the decimal points of all the numbers and convert them to integers."
|
||||
},
|
||||
{
|
||||
"subtitle": "Custom Map Functions",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['a', 'b', 'c']\n .map(a => [a.toUpperCase()]);\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>[['A'], ['B'], ['C']]</code></pre>",
|
||||
"<pre><code class='language-javascript'>['A', 'B', 'C']</code></pre>",
|
||||
"<pre><code class='language-javascript'>['a', 'b', 'c]</code></pre>",
|
||||
"<pre><code class='language-javascript'>'ABC'</code></pre>"
|
||||
],
|
||||
"answer": 0,
|
||||
"explanation": "The map function will return a new array with each element equal to the old element ran through a callback function. Our callback function takes our original element, changes it to a upper case, and then wraps it in an array; thus, leaving us with <code>[['A', 'B', 'C']]</code>"
|
||||
},
|
||||
{
|
||||
"subtitle": "Maps on Maps",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [[4, 1], [2, 0], [3, 3]]\n .map(a => \n a.map(b => b % 2)[0] + a.map(b => b - 1)[1]\n )\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>[[0, 1], [0, 0], [1, 1]]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[[0, 0], [0, -1], [1, 2]]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[1, 1, 2]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[0, -1, 3]</code></pre>"
|
||||
],
|
||||
"answer": 3,
|
||||
"explanation": "This answer can be explained by first looking at the example of what happens with the first element in our array, <code>[4, 1]</code>. Our first map callback will run a mod 2 map function over <code>[4, 1]</code> leaving us with a new array of <code>[0, 1]</code>. The second map call which is inside our callback will subtract 1 from every element, leaving us with <code>[3, 0]</code>. Last, we take element at index 0, <code>0</code>, and add it to element of index 1 from our second map function, <code>0</code>, leaving us with 0; thus, after the first iteration of the top level map function, we are left with an array that looks like so: <code>[1, [2, 0], [3, 3]]</code>. We simply keep doing that logic for the other elements until we finish: <code>[1, -1, [3, 3]]</code>, and <code>[1, -1, 3]</code>"
|
||||
},
|
||||
{
|
||||
"subtitle": "Words Containing 'a'",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['apple', 'dog', 'cat']\n .map((a, i) => \n a.indexOf('a') !== -1 ? i : null)\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>[0, -1, 1]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[0, null, 2]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[null, null, null]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[-1, null, 2]</code></pre>"
|
||||
],
|
||||
"answer": 1,
|
||||
"explanation": "This map example will return an array where each elements of the new array is either the original array index when the element contains the character 'a'; otherwise, an element of null for any words that do not have the character 'a'."
|
||||
},
|
||||
{
|
||||
"subtitle": "Accessing the Original Array Elements",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1, 2, 3]\n .map((a, _, o) => a + o[0])\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>[1, 2, 3]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[0, 0, 0]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[3, 2, 1]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[2, 3, 4]</code></pre>"
|
||||
],
|
||||
"answer": 3,
|
||||
"explanation": "This map example will add the value of the first element in the original array to all the other elements in the array."
|
||||
},
|
||||
{
|
||||
"subtitle": "More Map Hacking",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [8, 5, 3]\n .map((a, i, o) => o[o.length - i - i])\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>[3, 5, 8]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[5, 3, 8]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[8, 5, 3]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[3, 8, 5]</code></pre>"
|
||||
],
|
||||
"answer": 0,
|
||||
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
|
||||
},
|
||||
{
|
||||
"subtitle": "Custom Scoping",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['a', 'b', 'c']\n .map(function(a) { return this[a]; }, {a: 9, b: 3, c: 1})\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>['a', 'b', 'c']</code></pre>",
|
||||
"<pre><code class='language-javascript'>[9, 3, 1]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[3, 9, 1]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[{a: 9}, {b: 3}, {c: 1}]</code></pre>"
|
||||
],
|
||||
"answer": 1,
|
||||
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
|
||||
},
|
||||
{
|
||||
"subtitle": "Reversing in Map, Just Because",
|
||||
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1, 2, 3, 4, 5]\n .map((a, _, o) => o.reverse() && a)\nconsole.log(results);</code></pre>",
|
||||
"choices": [
|
||||
"<pre><code class='language-javascript'>[5, 4, 3, 2, 1]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[5, 2, 3, 5, 1]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[1, 2, 3, 4, 5]</code></pre>",
|
||||
"<pre><code class='language-javascript'>[1, 4, 3, 2, 5]</code></pre>"
|
||||
],
|
||||
"answer": 3,
|
||||
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
|
||||
}
|
||||
],
|
||||
"tests": [],
|
||||
"challengeType": 8
|
||||
}
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user