用于根据先前值过滤序列的惯用语clojure和Javascript表达式

时间:2015-02-07 06:09:16

标签: javascript clojure

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

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

我想得到这个输出:

9, 20

(上下文:这些值表示已应用某种样式的文本片段.4,9对表示用户选择的字符4,9(不包括)并单击“Bold”。当用户“Unblods”时每对中的第一个成员变为-1。因此,为了找到所有“活动”样式,我需要过滤那些带有-1的样式。

我正在寻找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

这是@CandiedOrange建议的内容(JS impl。使用underscore库):

_.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] })

评论:

  • 通过组合两个.filter调用可以缩短一点。尽管如此,我认为最好将它们分开,因为i % 2 == 0是impl的工件。而pair[0] >= 0是这里所需的“真正的商业逻辑”。
  • 这看起来有点冗长。我本来希望功能编程更好地处理这样的任务。在Clojure-land中有更好的解决方案吗?

编辑3

困扰我的是,非功能性(命令式)解决方案非常简单:

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

当然它不像Clojure解决方案那么简洁,但依赖于更少的构造,因此JS开发人员更有可能达到这个目的,而Clojure开发人员很可能会得到Clojure解决方案(需要熟悉->> partition first second mapfilter

4 个答案:

答案 0 :(得分:9)

在Clojure中:

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

编辑:@CandiedOrange请求的解释:

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

答案 1 :(得分:0)

最简单的解决方案

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);

答案 2 :(得分:0)

对于Javascript解决方案,也许是这样的。它似乎解决了您对Javascript解决方案的不喜欢。

&#13;
&#13;
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);
&#13;
<pre id="out"></pre>
&#13;
&#13;
&#13;

这些解决方案考虑了稀疏数组和-0的可能用途。它们还处理可能存在奇数个元素的情况。

另一种可能性。

&#13;
&#13;
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);
&#13;
<pre id="out"></pre>
&#13;
&#13;
&#13;

答案 3 :(得分:0)

使用underscore.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中的->线程宏。 filter保持第一个元素大于或等于零的对。并且map返回该对的第二个元素。 value提取chain的值。

Michael Fogus有一本关于功能性JavaScript的好书:Functional JavaScript: Introducing Functional Programming with Underscore.js