2017-01-29 3 views
0

У меня есть массив шагов, в примере я буду использовать буквы:уменьшая массив шагов до меньшего массива

let steps=['f', 'b', 'c', 'd', 'x', 'h', 'i' ] 

и функцию объединения, которая принимает два шага и возвращаю слит шаг, если он может объединить их или нуль, если он не может, в качестве примера будет Concat два последовательных букв:

function nextLetter(s){ 
    return s.replace(/([a-zA-Z])[^a-zA-Z]*$/, function(a) { 
     var c= a.charCodeAt(0); 
     if (c===90 || c===122) return null; else return String.fromCharCode(++c); 
     } 
    }); 
} 

// merge('x', 'a') -> null , marge('x', 'y') -> 'xy' 
function mergeSteps(s1, s2) { 
    if (s2==nextLetter(s1)) return s1+s2; else return null; 
} 

мне теперь нужно написать mergeStepsArray функции, это будет получить массив шагов и возвращает новый массив пытаясь объединить как можно больше последовательных шагов, с тем чтобы шаги массива выше:

mergeStepsArray(steps, mergeSteps); вернется ['f', 'bcd', 'x', 'hi' ]

Как я могу написать такую ​​функцию эффективно? Я пытался использовать Array.reduce, но я не могу заставить его работать в этом случае.

ПРИМЕЧАНИЕ: Мне нужен mergeStepsArray(steps, mergeSteps), который является общим и не знает особенностей его аргументов. Например шаги могут быть сделаны из цифр и mergeSteps мог return s2==s1*2 ? s1*s2 : null

Благодарности

+0

Может использовать разъяснение, если это слияние рекурсивны? IE ''bcd ...''? Или просто одна итерация? – Enfyve

+0

да, должно быть, я обновлю свой вопрос, thx – kofifus

+0

вопрос должен иметь больше смысла – kofifus

ответ

0

я закончил с:

var steps = ['f', 'b', 'c', 'd', 'x', 'h', 'i', 'z']; 
 

 
function mergeStep(x, y) { 
 
    if ((x.charCodeAt(x.length - 1) + 1) % 97 == y.charCodeAt(0) % 97) { 
 
    return x + y; 
 
    } else { 
 
    return null; 
 
    } 
 
} 
 

 
function mergeStepsArray(steps, mergeStep) { 
 
    let mergedSteps = []; 
 
    for (let i = 1, step = steps[0]; i <= steps.length; i++) 
 
    step = steps[i] && mergeStep(step, steps[i]) || mergedSteps.push(step) && steps[i] 
 
    return mergedSteps 
 
} 
 

 
alert(mergeStepsArray(steps, mergeStep))

0

Вы можете попробовать что-то подобное с уменьшить и раскол:

let steps=['f', 'b', 'c', 'd', 'x', 'h', 'i' ]; 
 

 

 
function mergeSteps(s1, s2) { 
 
    return s1.charCodeAt(0) - s2.charCodeAt(0) == 1 ? true : false; 
 
} 
 

 
var step1 = steps.reduce(function(acc, curr, ind, arr){ 
 
    if(ind > 0 && mergeSteps(curr, arr[ind - 1])){ 
 
     acc = acc + curr; 
 
    } 
 
    else { 
 
     acc = acc + "-" +curr; 
 
    } 
 
return acc; 
 
}).split("-"); 
 

 
console.log(step1);

+0

спасибо! Я использовал строки только в качестве примера, я ищу общую функцию mergeStepsArray (шаги, mergeSteps), которая затем может быть применена в этом случае. Можете ли вы преобразовать свое решение в такое? – kofifus

+0

Можете ли вы привести пример фактического ввода и вывода, который вы хотите преобразовать? – poushy

+0

те же ввод и вывод будут использоваться для тестирования, но мне нужна логика mergeStepsArray, которая будет реализована с точки зрения ее аргументов (то есть путем вызова mergeSteps), не зная тип элементов массива и т. Д. – kofifus

1

Эта работа даже если этапы: строки

let steps=['f', 'b', 'c', 'd', 'xgoog', 'h', 'i', 'd' ]; 
 

 
// check if the first character of b is just next the last character of a 
 
function valid(a, b) { 
 
    return a.charCodeAt(a.length - 1) + 1 === b.charCodeAt(0); 
 
} 
 

 

 
let result = []; 
 
// the first entry of steps as the current a 
 
let current = steps[0]; 
 
for(var i = 1; i < steps.length; i++) { 
 
    // if this step is valid add it to current to accumulate the result 
 
    if(valid(current, steps[i])) 
 
    current += steps[i]; 
 
    // if not then push the accumulated result into the array, and start another one from this step 
 
    else { 
 
    result.push(current); 
 
    current = steps[i]; 
 
    } 
 
} 
 
// push the last one 
 
result.push(current); 
 

 

 
console.log(result);

В ЦЕЛОМ:

Логика должна быть такой:

// reduceArray should take three parameters: 
// * arr: the array, 
// * check: the function responsible for the decision wether to merge or not (takes two parameters and check if they're mergeable) 
// * merge: the function that merges two elements (takes two parameters, merges them and return the result) 
function reduceArray(arr, checkFn, mergeFn) { 
    // check for errors 
    if(!arr || !(arr instanceof Array) || arr.length == 0) return []; 
    if(!checkFn || typeof checkFn != "function") return []; 
    if(!mergeFn || typeof mergeFn != "function") return []; 

    var result = []; 

    // current should take the value of the first item in the array so ... 
    var current = arr[0]; 
    // the loop starts at 1 
    for(var i = 1; i < arr.length; i++) { 
     // always check if current is mergeable with arr[i] 
     if(checkFn(current, arr[i])){ 
      // if so, store the merge result in current and re-check again for the next element 
      current = mergeFn(current, arr[i]); 
     } 
     else { 
      // if not store the result, and start another check-merge starting from this index (arr[i]) 
      result.push(current); 
      current = arr[i]; 
     } 
    } 
    // don't forget to store the last element (merged or not) 
    result.push(current) 

    return result; 
} 


function myCheck(a, b) { 
    /* check if a could be merged with b */ 
    /* must return true or false */ 
} 

function myMerge(a, b) { 
    /* merge a with b and return the result */ 
} 

// and then call reduceArray like this: 
var myArr = new Array(); 
// ... 
var result = reduceArray(myArr, myCheck, myMerge); 
// or like this 
var result = reduceArray(myArr, function(a, b){ 
    /* return true or false depending on whether a and b are mergeable or not */ 
}, function(a, b){ 
    /* merge a and b and return the result */ 
}) 

Другой подход:

Я также добавил проверку на обратный вызов (для проверьте, является ли это действительным обратным вызовом).

// reduceArray should take three parameters: 
// * arr: the array, 
// * mergeStepsFn: takes two parameter and return the result if they're mergeable, null othrwise 
function reduceArray(arr, mergeStepsFn) { 
    // check for errors 
    if(!arr || !(arr instanceof Array) || arr.length == 0) return []; 
    if(!mergeStepsFn || typeof mergeStepsFn != "function") return []; 

    var result = []; 

    var current = arr[0]; 
    for(var i = 1; i < arr.length; i++) { 
     // get the result of merging current with the arr[i] 
     var mergeResult = mergeStepsFn(current, arr[i]); 
     // if merge was successful 
     if(mergeResult !== null){ // should compare against null since we have no idea about the data types 
      // if so, store the merge result in current 
      current = mergeResult; 
     } 
     else { 
      // if not store the accumulated result, and start another check-merge starting from this index (arr[i]) 
      result.push(current); 
      current = arr[i]; 
     } 
    } 
    // don't forget to store the last element (merged or not) 
    result.push(current) 

    return result; 
} 


function myMergeStepsFunction(a, b) { 
    /* if a is mergeable with b then return the merge result, if not return null */ 
} 

// and then call reduceArray like this: 
var myArr = new Array(); 
// ... 
var result = reduceArray(myArr, myMergeStepsFunction); 
// or like this 
var result = reduceArray(myArr, function(a, b){ 
    /* if a is mergeable with b then return the merge result, if not return null */ 
}); 
+0

Мне нужен mergeStepsArray (шаги, mergeSteps), который является общим и не знает специфики его аргументов – kofifus

+0

@kofifus Я обновил свой ответ. Проверьте раздел ** IN GENERAL ** выше! –

+0

thx ibrahim .... – kofifus

1

вы можете использовать что-то вроде этого

var steps = ['f', 'b', 'c', 'd', 'x', 'h', 'i' ]; 

function checkStepSingle(x, y){ 
    if((x.charCodeAt(x.length-1)+1) % 97 == y.charCodeAt(0)%97){ 
    return x + y; 
    } 
    else{ 
    return null; 
    } 
} 

function mergeArray(array, mergeSteps){ 
    var returnArray = array.slice(); 
    for(i = 0; i+1 < returnArray.length; i++){ 
    var step = mergeSteps(returnArray[i], returnArray[i+1]); 
    if(step != null){ 
     returnArray[i] = step; 
     returnArray.splice(i+1, 1); 
     i = i-1; 
    } 
    } 

    return returnArray; 
} 
console.log(mergeArray(steps, checkStepSingle)) 
console.log(steps) 

Но если вы хотите использовать также заглавные буквы, вы должны изменить номер 97 на 65.

Другой подход Этот путь от спины к фронту. Вы просто добавляете элементы, если их нельзя уменьшить с помощью следующего. Чтобы быть на 100% уверенным, вы должны добавить инструкцию if else в начале, чтобы убедиться, что вы не запускаете нулевой массив.

var steps = ['f', 'b', 'c', 'd', 'x', 'h', 'i' ]; 

function checkStepSingle(x, y){ 
    if((x.charCodeAt(x.length-1)+1) % 97 == y.charCodeAt(0)%97){ 
    return x + y; 
    } 
    else{ 
    return null; 
    } 
} 

function mergeArray(array, mergeSteps){ 
    var tmpArray = []; 
    var tmp = array[0]; 
    for(i = 0; i+1 < array.length; i++){ 
    var step = mergeSteps(tmp, array[i+1]); 
    if(step != null){ 
     tmp = step; 
    } 
    else{ 
     tmpArray.push(tmp); 
     tmp = array[i+1]; 
    } 
    } 
    tmpArray.push(tmp); 

    return tmpArray; 
} 
console.log(mergeArray(steps, checkStepSingle)) 
console.log(steps) 
+0

Мне нужен mergeStepsArray (шаги, mergeSteps), который является общим и не знает специфики его аргументов – kofifus

+0

, поэтому вы можете добавить еще один параметр в mergeArray, который является функцией, и использовать его вместо mergeSteps. – Leo

+0

Я не понимаю ваш код, есть checkStepSingle, который никогда не называется?см. мой вопрос. Мне нужна функция mergeStepsArray (шаги, mergeSteps) – kofifus

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