Почему [‘1’, ‘7’, ’11’].map(parseint) возвращает [1, nan, 3] в javascript?

sort

Данный метод
сортирует массив по тому критерию, который указывается в ее необязательной callback-функции:

ar.sort(function(a, b) {
if (a > b) return 1; // если первое значение больше второго
if (a == b) return 0; // если равны
if (a < b) return -1; // если первое значение меньше второго
})

Сортировка
выполняется непосредственно внутри массива ar, но функция
также и возвращает отсортированный массив, правда это возвращаемое значение,
обычно игнорируется. Например:

let dig = 4, 25, 2;
 
dig.sort();
console.log( dig );

И получим
неожиданный результат: 2, 25, 4. Дело в том, что по умолчанию метод sort рассматривает
значения элементов массива как строки и сортирует их в лексикографическом
порядке. В результате, строка «2» < «4» и «25» < «4», отсюда и результат.
Для указания другого критерия сортировки, мы должны записать свою callback-функцию:

dig.sort(function(a, b) {
    if(a > b) return 1;
    else if(a < b) return -1;
    else return ;
});

Теперь
сортировка с числами проходит так как нам нужно. Кстати, чтобы изменить
направление сортировки (с возрастания на убывание), достаточно поменять знаки
больше и меньше на противоположные. И второй момент: callback-функция не
обязательно должна возвращать именно 1 и -1, можно вернуть любое положительное,
если a>b и отрицательное
при a<b. В частности,
это позволяет переписать приведенный выше пример вот в такой краткой форме:

dig.sort( (a, b) => a-b );

По аналогии
можно формировать и более сложные алгоритмы сортировки самых разных типов данных:
строк, чисел, объектов, булевых переменных и так далее.

Creating a Tally with the Reduce Method In JavaScript​

Use it when: You have a collection of items and you want to know how many of each item are in the collection.

const fruitBasket = ;const count = fruitBasket.reduce( (tally, fruit) => {  tally = (tally || 0) + 1 ;  return tally;} , {})count // { banana: 2, cherry: 3, orange: 3, apple: 2, fig: 1 }

To tally items in an array our initial value must be an empty object, not an empty array like it was in the last example.

Since we are going to be returning an object we can now store key-value pairs in the total.

fruitBasket.reduce( (tally, fruit) => {  tally = 1;  return tally;}, {})

On our first pass, we want the name of the first key to be our current value and we want to give it a value of 1.

This gives us an object with all the fruit as keys, each with a value of 1. We want the amount of each fruit to increase if they repeat.

To do this, on our second loop we check if our total contain a key with the current fruit of the reducer. If it doesn’t then we create it. If it does then we increment the amount by one.

fruitBasket.reduce((tally, fruit) => {  if (!tally) {    tally = 1;  } else {    tally = tally + 1;  }  return tally;}, {});

I rewrote the exact same logic in a more concise way up top.

Silly Mistakes to avoid

If you don’t pass in an initial value, reduce will assume the first item in your array is your initial value. This worked fine in the first few examples because we were adding up a list of numbers.

If you’re trying to tally up fruit, and you leave out the initial value then things get weird. Not entering an initial value is an easy mistake to make and one of the first things you should check when debugging.

Another common mistake is to forget to return the total. You must return something for the reduce function to work. Always double check and make sure that you’re actually returning the value you want.

Tools, Tips & References

  • Everything in this post came from a fantastic video series on egghead called Introducing Reduce. I give Mykola Bilokonsky full credit and I am grateful to him for everything I now know about using the Reduce Method In JavaScript​. I have tried to rewrite much of what he explains in my own words as an exercise to better understand each concept. Also, it’s easier for me to reference an article, as opposed to a video, when I need to remember how to do something.
  • The MDN Reduce documentation labels what I called a total the . It is important to know this because most people will refer to it as an accumulator if you read about it online. Some people call it as in previous value. It all refers to the same thing. I found it easier to think of a total when I was learning reduce.
  • If you would like to practice using reduce I recommend signing up to freeCodeCamp and completing as many of the as you can using reduce.
  • If the ‘const’ variables in the example snippets are new to you I wrote another article about ES6 variables and why you might want to use them.
  • I also wrote an article called The Trouble With Loops that explain how to use map() and filter() if the are new to you.

Суть рекурсии

В общем, рекурсивный подход подразумевает разделение сложной задачи, на один простой шаг к её решению и оставшуюся часть, которая становится упрощённой версией той же задачи. Затем этот процесс повторяется. Каждый раз вы совершаете один шаг, до тех пор, пока задача упростится до одного простейшего решения (его называют «базовым случаем»). Простейшее решение нашего базового случая с шагами, которые мы предприняли, чтобы добраться до него, образуют решение нашей первоначальной задачи.


Мы каждый раз разделяем задачу «P» на шаги и оставшуюся упрощённую задачу той же формы, что и оригинал, пока не достигнем простого решения небольшой проблемы (базовый случай).

Предположим, у нас есть фактические данные определённого типа, назовём их dₒ. Идея рекурсии состоит в том, чтобы предположить, что мы уже решили задачу или вычислили желаемую функцию f для всех форм этого типа данных. Каждая из этих форм проще общей сложности dₒ, которую нам нужно определить. Следовательно, если мы можем найти способ выражения f(dₒ), исходя из одной или нескольких частей f(d), где все эти d проще, чем dₒ, значит мы нашли решение для f(dₒ). Мы повторяем этот процесс, и рассчитываем, что в какой-то момент оставшиеся f(d) станут настолько простыми, что мы сможем легко реализовать фиксированное, окончательное решение для них. В итоге, решением исходной задачи станет поэтапное решение более простых задач.

В приведённом выше примере (про написание статьи), данными является текст, содержащийся в документе, который я должен написать, а степень сложности — это длина документа. Это немного надуманный пример, но если предположить, что я уже решил задачу f(900) (написать 900 слов), то все, что мне нужно сделать, чтобы решить f(1000), ― это написать 100 слов и выполнить решение для 900 слов, f(900).

Давайте рассмотрим пример получше: с числами Фибоначчи, где 1-е число равно 0, второе равно 1, а nᵗʰ число равно сумме двух предыдущих. Предположим, у нас есть функция Фибоначчи, которая сообщает нам nᵗʰ число:

fib(n):  if n == 0:    return 0  if n == 1:    return 1  else:    return fib(n-1) + fib(n-2)

Как будет выглядеть выполнение такой функции? Возьмём для примера :

Визуализация древа рекурсии, показывающая рекурсивное вычисление, которое приводит к fib(4) = 3

Обратите внимание, что вычисление сначала выполняется в глубину

В процессе рекурсивного решения задачи полезно повторять мантру: «Притворяйся, пока это не станет правдой», то есть делай вид, что ты уже решил более простую часть задачи. Затем попытайся уменьшить большую часть задачи, чтобы использовать решение упрощённой части. Подходящая для рекурсии задача, на самом деле должна иметь небольшое количество простых частей, которые нужно решить явно. Другими словами, метод сокращения до более простой задачи может быть использован для решения любого другого случая. Это можно проиллюстрировать на примере чисел Фибоначчи, где для определения мы действуем, как будто мы уже рассчитали и В тоже время мы рассчитываем, что эти каскады и упрощения приведут к более простым случаям, пока мы не достигнем и , которые имеют фиксированные и простые решения.


«Притворяйся, пока это не станет правдой»

Рекурсивная стратегия

Рекурсивный подход — дело тонкое, и зависит от того, какую проблему вы пытаетесь решить. Тем не менее, есть некоторая общая стратегия, которая поможет вам двигаться в правильном направлении. Эта стратегия состоит из трёх шагов:

  1. Упорядочить данные
  2. Решить малую часть проблемы
  3. Решить большую часть проблемы

Как я уже говорил, я думаю, что для обучения полезно приводить пример, но помните, что рекурсивный подход зависит от конкретной задачи. Поэтому старайтесь сосредоточиться на общих принципах. Мы рассмотрим простой пример с реверсом строки. Мы напишем функцию которая будет работать так: . Я рекомендую вернуться назад и посмотреть, как эти шаги применяются к функции Фибоначчи, а затем попробовать применить их на других примерах (в интернете можно найти много упражнений).

Flattening an array of arrays with the Reduce Method In JavaScript​​

We can use reduce to flatten nested amounts into a single array.

We set the initial value to an empty array and then concatenate the current value to the total.

const data = , , ];const flat = data.reduce((total, amount) => {  return total.concat(amount);}, []);flat // 

More often than not, information is nested in more complicated ways. For instance, lets say we just want all the colors in the data variable below.

const data = },   {a: 'tired', b: 'panther', c: },   {a: 'sad', b: 'goldfish', c: }];

We’re going to step through each object and pull out the colours. We do this by pointing amount.c for each object in the array. We then use a forEach loop to push every value in the nested array into out total.

const colors = data.reduce((total, amount) => {  amount.c.forEach( color => {      total.push(color);  })  return total;}, [])colors //

If we only need unique number then we can check to see of the number already exists in total before we push it.

const uniqueColors = data.reduce((total, amount) => {  amount.c.forEach( color => {    if (total.indexOf(color) === -1){     total.push(color);    }  });  return total;}, []);uniqueColors // 

A Basic Reduction

Use it when: You have an array of amounts and you want to add them all up.

const euros = ;const sum = euros.reduce((total, amount) => total + amount); sum // 118.11

How to use it:

  • In this example, Reduce accepts two parameters, the total and the current amount.
  • The reduce method cycles through each number in the array much like it would in a for-loop.
  • When the loop starts the total value is the number on the far left (29.76) and the current amount is the one next to it (41.85).
  • In this particular example, we want to add the current amount to the total.
  • The calculation is repeated for each amount in the array, but each time the current value changes to the next number in the array, moving right.
  • When there are no more numbers left in the array the method returns the total value.

Map and Filter as Reductions

If you can use the reduce function to spit out an average then you can use it any way you want.

For example, you could double the total, or half each number before adding them together, or use an if statement inside the reducer to only add numbers that are greater than 10. My point is that the Reduce Method In JavaScript​ gives you a mini CodePen where you can write whatever logic you want. It will repeat the logic for each amount in the array and then return a single value.

The thing is, you don’t always have to return a single value. You can reduce an array into a new array.

For instance, lets reduce an array of amounts into another array where every amount is doubled. To do this we need to set the initial value for our accumulator to an empty array.

The initial value is the value of the total parameter when the reduction starts. You set the initial value by adding a comma followed by your initial value inside the parentheses but after the curly braces (bolded in the example below).

const average = euros.reduce((total, amount, index, array) => {  total += amount  return total/array.length}, 0);

In previous examples, the initial value was zero so I omitted it. By omitting the initial value, the total will default to the first amount in the array.

By setting the initial value to an empty array we can then push each amount into the total. If we want to reduce an array of values into another array where every value is doubled, we need to push the amount * 2. Then we return the total when there are no more amounts to push.

const euros = ;const doubled = euros.reduce((total, amount) => {  total.push(amount * 2);  return total;}, []);doubled // 

We’ve created a new array where every amount is doubled. We could also filter out numbers we don’t want to double by adding an if statement inside our reducer.

const euro = ;const above30 = euro.reduce((total, amount) => {  if (amount > 30) {    total.push(amount);  }  return total;}, []);above30 // 

These operations are the map and filter methods rewritten as a reduce method.

For these examples, it would make more sense to use map or filter because they are simpler to use. The benefit of using reduce comes into play when you want to map and filter together and you have a lot of data to go over.

If you chain map and filter together you are doing the work twice. You filter every single value and then you map the remaining values. With reduce you can filter and then map in a single pass.

Use map and filter but when you start chaining lots of methods together you now know that it is faster to reduce the data instead.

Piping with Reduce

An interesting aspect of the reduce method in JavaScript is that you can reduce over functions as well as numbers and strings.

Let’s say we have a collection of simple mathematical functions. these functions allow us to increment, decrement, double and halve an amount.

function increment(input) { return input + 1;}function decrement(input) { return input — 1; }function double(input) { return input * 2; }function halve(input) { return input / 2; }

For whatever reason, we need to increment, then double, then decrement an amount.

You could write a function that takes an input, and returns (input + 1) * 2 -1. The problem is that we know we are going to need to increment the amount three times, then double it, then decrement it, and then halve it at some point in the future. We don’t want to have to rewrite our function every time so we going to use reduce to create a pipeline.

A pipeline is a term used for a list of functions that transform some initial value into a final value. Our pipeline will consist of our three functions in the order that we want to use them.

let pipeline = ;

Instead of reducing an array of values we reduce over our pipeline of functions. This works because we set the initial value as the amount we want to transform.

const result = pipeline.reduce(function(total, func) {  return func(total);}, 1);result // 3

Because the pipeline is an array, it can be easily modified. If we want to increment something three times, then double it, decrement it , and halve it then we just alter the pipeline.

var pipeline = ;

The reduce function stays exactly the same.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector