用于根据上一个值筛选序列的惯用clojure和Javascript表达式

Idiomatic clojure and Javascript expression for filtering a sequence based on the previous value

本文关键字:clojure 表达式 Javascript 上一个 筛选 用于      更新时间:2023-09-26

所以我有一个整数序列。我想选择其他所有元素,但前提是它前面的元素是正的。例如,给定以下输入:

4, 9, -1, 8, 3, 20, -1, 7

我想得到这个输出:

9, 20

(上下文:这些值表示应用了特定样式的文本段。4,9对表示用户选择的字符4,9(不包括)并单击"粗体"。当用户"取消绑定"时,每对中只有第一个成员变为-1。因此,为了找到所有"活动"样式,我需要过滤那些带有-1 out)的样式

我正在寻找Javascript和Clojure解决方案(因为这段代码需要在浏览器端和服务器端运行)。

以下是一个可能的JS impl.:

styleList.map(function(curr, i) {
  if (i % 2 == 1) 
    return (styleList[i - 1] >= 0) ? curr : -1;
  else
    return -1;
}).filter(function(curr) { return curr >= 0 })

我不喜欢这个解决方案:我传递给.map()的函数使用索引i来检查以前的值。这感觉很尴尬。我正在寻找一个更实用的解决方案。

编辑

这是另一个我不喜欢的解决方案(再次:由于arr对象的突变,功能不太好):

var arr = [];
styleList.reduce(function(prev, curr) {
  arr.push(prev == -1 ? -1 : curr);
  return curr;
});
arr.filter(function(curr, i) {
  return i % 2 == 1 && curr >= 0;
});

编辑2

以下是@CandidOrange的建议(JS impl.使用下划线库):

_.zip(styleList, styleList.slice(1)).
  slice(0, -1).
  filter(function(pair, i) { return i % 2 == 0 }).
  filter(function(pair) { return pair[0] >= 0 }).
  map(function(pair) { return pair[1] })

评论:

  • 这可以通过组合两个CCD_ 4调用来缩短一点。不过,我认为最好将它们分开,因为i % 2 == 0是impl的工件。而CCD_ 6是这里所需要的"真正的业务逻辑"
  • 这看起来有点冗长。我希望函数式编程能更好地处理这样的任务。在Clojure的土地上有更好的解决方案吗

编辑3

这里困扰我的是,非功能(命令式)解决方案非常琐碎:

var result = [];
styleList.forEach(function(curr, i) {
  if (i % 2 == 1 && styleList[i - 1] >= 0)
    result.push(curr);
});

当然,它不像Clojure解决方案那样简洁,但依赖于更少的构造,因此JS开发人员比Clojure开发人员更有可能实现这一点(需要熟悉->> partition first second mapfilter

在Clojure:中

(->> your-list 
     (partition 2)
     (filter #(pos? (first %)))
     (map second))

编辑:根据@CandidOrange:的要求进行解释

  • 将列表分成两组
  • 过滤配对,只保留第一个元素为正的配对
  • 将每一对转换为单个项目(第二个)

最简单的解决方案

var array=[4, 9, -1, 8, 3, 20, -17];
var s;
for(var i=0; i < array.length ; i+=2) {
  if(array[i] < 0 || array[i+1]<0){ 
    continue;
  } else {
    if(!s) {
      s=array[i+1];  
    } else {    
      s=s+","+array[i+1];  
    }   
  }
}
alert(s);

使用undercore.js:

var styleList = [4, 9, -1, 8, 3, 20, -1, 7];
var pairs = _.zip(_.filter(styleList, function(val, idx) { return idx % 2 == 0; }), 
                  _.filter(styleList, function(val, idx) { return idx % 2 == 1; }));
_.chain(pairs)
.filter(function (pair) { return pair[0] >= 0; })
.map(function (pair) { return pair[1]; })
.value();

pairs仅包含您感兴趣的对:[[4,9],[-1,8],[3,20],[-1,7]]chain函数类似于Clojure中的->线程宏。CCD_ 17保持第一元素大于或等于零的对。并且CCD_ 18正在返回该对中的第二个元素。CCD_ 19提取CCD_。

Michael Fogus有一本关于函数式JavaScript的好书:函数式JavaScript:使用Undercore.js 介绍函数式编程

对于Javascript解决方案来说,可能是这样的。它似乎解决了您对Javascript解决方案的反感。

function checkObjectCoercible(inputArg) {
    var type = typeof inputArg;
    if (type === 'undefined' || inputArg === null) {
        throw new TypeError('Cannot convert argument to object');
    }
    return inputArg;
}
Object.defineProperty(Number, 'isPositive', {
    value: function (value) {
        if (typeof value !== 'number') {
            return false;
        }
        return value === 0 ? (1 / value) === Infinity : value > 0;
    }
});
Object.defineProperty(Array.prototype, 'groupsOf', {
    value: function (num) {
        var object = Object(checkObjectCoercible(this)),
            length = object.length,
            count = num >>> 0,
            newList = [],
            index,
            group,
            idx;
        if (length && count) {
            for (idx = 0; idx < length; idx += count) {
                group = [];
                group.length = count;
                for (index = 0; index < count; index += 1) {
                    group[index] = object[idx + index];
                }
                newList.push(group);
            }
        }
        return newList;
    }
});
var styleList = [4, 9, -1, 8, 3, 20, -1, 7],
    out = styleList.groupsOf(2).filter(function (pair) {
        return Number.isPositive(pair[0]) && typeof pair[1] === 'number';
    }).map(function (pair) {
        return pair[1];
    });
document.getElementById('out').textContent = JSON.stringify(out, null, 2);
<pre id="out"></pre>

这些解决方案考虑了稀疏阵列和CCD_ 21的可能使用。它们还处理可能存在奇数个元素的情况。

还有一种可能性。

function checkObjectCoercible(inputArg) {
    var type = typeof inputArg;
    if (type === 'undefined' || inputArg === null) {
        throw new TypeError('Cannot convert argument to object');
    }
    return inputArg;
}
Object.defineProperty(Number, 'isPositive', {
    value: function (value) {
        if (typeof value !== 'number') {
            return false;
        }
        if (value === 0) {
            return (1 / value) === Infinity;
        }
        
        return value > 0;
    }
});
function pairByIndex(acc, item, index) {
    var key = Math.floor(index / 2);
    if (!acc[key]) {
        acc[key] = [item];
        acc[key].length = 2;
    } else {
        acc[key][1] = item;
    }
    return acc;
}
Object.defineProperty(Array.prototype, 'toPairs', {
    value: function () {
        return checkObjectCoercible(this).reduce(pairByIndex, []);
    }
});
function firstEntry(pair) {
    return pair[0];
}
function secondEntry(pair) {
    return pair[1];
}
function firstEntryIsPositive(pair) {
    return Number.isPositive(firstEntry(pair));
}
var styleList = [4, 9, -1, 8, 3, 20, -1, 7],
    out = styleList.toPairs().filter(firstEntryIsPositive).map(secondEntry);
document.getElementById('out').textContent = JSON.stringify(out, null, 2);
<pre id="out"></pre>