将一系列步骤减少到一个较小的数组

时间:2017-01-29 23:10:51

标签: javascript ecmascript-6

我有一系列步骤,例如我将使用字母:

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

和一个合并函数,它接受两个步骤并返回一个合并的步骤,如果它可以合并它们或null,如果它不能,例如它将连续两个字母:

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

谢谢

4 个答案:

答案 0 :(得分: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);
&#13;
&#13;
&#13;

一般情况:

逻辑应该是这样的:

// 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 */
});

答案 1 :(得分:1)

你可以使用这样的东西

>>> myList = ["l", "r", "e"]
>>> myList.insert(0, "a")
['a', 'l', 'r', 'e']

但是如果你想使用大写字母,你必须将数字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 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)

答案 2 :(得分:0)

你可以尝试使用reduce和split:

&#13;
&#13;
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);
&#13;
&#13;
&#13;

答案 3 :(得分: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))