2016-10-31 1 views
1

Недавно я влюбился в функциональное программирование и начал изучать ramda.js, но пока не могу понять функционального мышления. У меня есть 2 массива строк (они фактически разделены строки), и я хочу найти, сколько символов в первой строке равно тем, которые находятся в одной позиции во второй строке. я бы Настоятельно сделать что-то действительно просто вдоль линий:Сравнивая 2 массива и находив равные значения с помощью Ramda

let counter = 0 
for(let i = 0; i < array.length; i++){ 
    if(firstArray[i] === secondArray[i]) counter++ 
} 

но как бы я сделать это с помощью ramda?

ответ

4

"... используя rambda"

Вот один как вы можете это сделать - есть множество других способов ...

const a = 
    'abcdefg' 

const b = 
    'abcxyzg' 

const countEqualChars = (a, b) => 
    R.sum(R.zipWith(R.equals, a, b)) 

countEqualChars(a,b) 
// 4 

Но ...

Это, по сути, неправильный путь для подхода к функциональному программированию. Забудьте Rambda, пока у вас не будет здравого смысла, как рассуждать о программах функционально. Вы никогда не сможете оценить удобство Рамбы, если вы не знаете, как все работает на фундаментальном уровне.

Начать изучение рекурсии как альтернативы for/while Петли. Там нет ничего плохого с петлями, но рекурсия позволит вам выразить вещи более хорошим способом иногда ...

const a = 
 
    'abcdefg' 
 

 
const b = 
 
    'abcxyzg' 
 

 
const countEqualChars = ([ x, ...xs ], [ y, ...ys ]) => 
 
{ 
 
    if (x === undefined || y === undefined) 
 
    return 0 
 
    else if (x === y) 
 
    return 1 + countEqualChars (xs, ys) 
 
    else 
 
    return countEqualChars (xs, ys) 
 
} 
 

 
console.log (countEqualChars (a, b)) 
 
// 4

Теперь мы видим, что эта функция делает совсем немного. Мы проверяем массивы по одному элементу за раз, сравниваем и подсчитываем. Возможно, мы могли бы разбить это на некоторые отдельные задачи, чтобы наша функция была немного более удобной с течением времени. Давайте начнем с функцией, которая позволяет нам паре равные показатели двух массивов ...

const zip = ([ x, ...xs ], [ y, ...ys ]) => 
 
    x === undefined && y === undefined 
 
    ? [] 
 
    : [ [ x, y ] ] .concat (zip (xs, ys)) 
 

 
console.log (zip ([ 1, 2, 3 ], [ 'a', 'b', 'c' ])) 
 
// [ [ 1, 'a' ] 
 
// , [ 2, 'b' ] 
 
// , [ 3, 'c' ] 
 
// ]

Далее, можно использовать встроенный в filter функции, чтобы сделать новый массив, содержащий только вещи, которые мы хотим

const xs = 
 
    [ 1, 1, 2, 2, 3, 3, 4, 4 ] 
 

 
const justThrees = 
 
    xs.filter (x => x === 3) 
 

 
console.log (justThrees) 
 
// [ 3, 3 ]

Сочетание этих zip и filter страты, мы можем паре каждый индекс из строки, а затем удалить пары, которые не соответствуют ...

const zip = ([ x, ...xs ], [ y, ...ys ]) => 
 
    x === undefined && y === undefined 
 
    ? [] 
 
    : [ [ x, y ] ] .concat (zip (xs, ys)) 
 
} 
 

 
const eq = (x, y) => 
 
    x === y 
 

 
const apply = f => xs => 
 
    f (...xs) 
 

 
const a = 
 
    'abcdefg' 
 

 
const b = 
 
    'abcxyzgh' 
 

 
const matches = 
 
    zip (a, b) .filter (apply (eq)) 
 

 
console.log (matches) 
 
// [ [ 'a', 'a' ] 
 
// , [ 'b', 'b' ] 
 
// , [ 'c', 'c' ] 
 
// , [ 'g', 'g' ] 
 
// ]

Теперь все, что осталось, подсчитывая совпадающие пары.Мы будем делать все это в функции тоже, так что вы можете повторно использовать его по мере необходимости

const zip = ([ x, ...xs ], [ y, ...ys ]) => 
 
    x === undefined && y === undefined 
 
    ? [] 
 
    : [ [ x, y ] ] .concat (zip (xs, ys)) 
 

 
const eq = (x, y) => 
 
    x === y 
 

 
const apply = f => xs => 
 
    f (...xs) 
 

 
const countEqualChars = (a, b) => 
 
    zip (a, b) 
 
    .filter (apply (eq)) 
 
    .length 
 

 
console.log (countEqualChars ('abcdefg', 'abcxyzgh')) 
 
// 4

самое главное ...

Вы увидите, что решение, полученное нами вручную, немного разных, чем тот, который мы использовали с Rambda. Это потому, что программирование не является волшебным, и вы будете изобретать много своих собственных инструментов, прежде чем осознавать, какие другие инструменты существуют или понимать, что они делают.

Есть сотни способов решить проблему, которую я только что сделал, и есть компромиссы, которые я рассматривал при каждом выборе, который я сделал. Ваша цель состоит в том, чтобы превратить вашу программу в ее составные части и узнать компромиссы с течением времени.

Сравните это с тем, чтобы понять, почему какая-то функция существует в какой-то библиотеке, чтобы вы могли угадать, где ее использовать ... Вы получите хорошее функциональное программирование, сделав это, а не путем копирования/вставки умных людей Rambda one -liners. Как только вы поймете , почемуequals, zipWith и sum существуют, вы будете знать, когда их использовать.

Позволь мне знать, если я могу помочь прояснить что-нибудь еще^_^

+1

Я не мог бы желать более полной лучшей мысли ответ. Большое спасибо ^^. –

1

Я не могу конкурировать с другим, отличным ответом, но не забывайте array прототип имеет много полезных методов, таких как filter или reduce!

var countMatches = (a, b) => a.reduce((sum, c, i) => 
 
    b[i] === c 
 
    ? ++sum 
 
    : sum 
 
, 0); 
 

 
var set1 = "1234678".split(""); 
 
var set2 = "1234568".split(""); 
 
console.log(countMatches(set1, set2));

+0

Хорошее практическое применение 'reduce' - моим единственным советом было бы вернуть' sum + 1' вместо 'sum ++', так как числа все равно неизменяемы. – naomik

+0

Я не думал об этом. Я довольно часто использую стандартные методы массива map/reduce/filter, но много времени внутри функций становится очень большим, и мне не нравится использовать индексы в списке параметров. Хорошее решение, хотя –

Смежные вопросы