简体   繁体   English

javascript中链接方法的复杂性

[英]Complexity of chaining methods in javascript

I have a problem to determine the complexity of my algorithm because it use features of ES6 and of course they are chained methods.我有一个问题来确定我的算法的复杂性,因为它使用ES6 的特性,当然它们是链式方法。 I already know some of basic complexity of those method for example the complexity of Array.prototype.map is O(n) .我已经知道这些方法的一些基本复杂性,例如Array.prototype.map的复杂性是 O(n) But when we want to determine a complexity of an algorithm, how do we manage chained method ?但是当我们想要确定一个算法的复杂度时,我们如何管理链式方法呢?

For example, consider we have a function which return for an array the sum of its positive numbers例如,考虑我们有一个函数,它为数组返回其正数之和

 let sumPositive = arr => arr.filter(i => i > 0).reduce((a, b) => a + b, 0); console.log(sumPositive([1, 2, 3, -4])); // 6 console.log(sumPositive([1, 2, 3, 4])); // 10

Therefore, what is the complexity of that function ?因此,该函数复杂度是多少?

Another example is this algorithm which for a given string, return the counts of each character in the string另一个例子是这个算法,对于给定的字符串,返回字符串中每个字符的计数

 let charCount = str => str.split('').map( (c,_,str) => str.filter(i => i===c) ).reduce((a, b) => a.hasOwnProperty(b[0]) ? a : ({...a, [b[0]]: b.length}), {}); console.log(charCount("hi")); // {"h": 1, "i": 1} console.log(charCount("hello to you")); // {"h": 1, "e": 1, "l": 2, "o": 3, " ": 2, "t": 1, "y": 1, "u": 1}

So for this second I need to know especially its complexity because we are dealing with nested method like the filter which is being call inside a map因此,对于这一秒,我需要特别了解它的复杂性,因为我们正在处理嵌套方法,例如在地图中调用的过滤器

So any general method to determine the complexity of such algorithm are welcome.因此,欢迎任何确定此类算法复杂度的通用方法。

Note : All the complexity in this question is the time-complexity not space注意:这个问题的所有复杂度都是时间复杂度而不是空间

Thanks谢谢

Chaining methods is actually just for convenience.链接方法实际上只是为了方便。 map() or filter() returns an array. map()filter()返回一个数组。 Now you can first put a name on the array, like let result = arr.map(...) and then do other stuff on that result array, or you can directly do something on the array returned by map() (or filter() ), like map().filter().<more chaining if you want> .现在你可以先在数组上放一个名字,比如let result = arr.map(...)然后在那个result数组上做其他的事情,或者你可以直接在map()返回的数组上做一些事情(或filter() ),例如map().filter().<more chaining if you want>

So, it's equivalent to a sequential execution.所以,它相当于一个顺序执行。 Consider this example,考虑这个例子,

let sumPositive = arr => arr.filter(i => i > 0)
                            .reduce((a, b) => a + b, 0);

let arr = [1, 2, 3, -4];

let filteredArray = arr.filter(i => i > 0); // O(n)
let reducedResult = filteredArray.reduce((a, b) => a + b, 0); // O(n)

console.log(sumPositive(arr)); // 6
console.log(reducedResult) // 6

Now you see filter() takes O(n) and then reduce() takes O(n) , so you get O(n) + O(n) ==> O(n) as your final time complexity.现在你看到filter()需要O(n)然后reduce()需要O(n) ,所以你得到O(n) + O(n) ==> O(n)作为你的最终时间复杂度。

I hope you can similarly find complexity for the second example.我希望你能同样找到第二个例子的复杂性。 If you need assistance, let me know in the comments.如果您需要帮助,请在评论中告诉我。

@Ajay Dabas answered your question; @Ajay Dabas 回答了您的问题; I'm answering your question in the comments:我在评论中回答你的问题:

So could you give me an example of what I can do to improve the code or some useful links所以你能给我一个例子来说明我可以做些什么来改进代码或一些有用的链接

Your first example isn't going to get any simpler, but you could decrease the time complexity of your second algorithm:您的第一个示例不会变得更简单,但您可以降低第二个算法的时间复杂度:

let charCount = str =>  str.split('')
  .map((c,_,str) => str.filter(i => i===c))
  .reduce((a, b) => a.hasOwnProperty(b[0]) ? a : ({...a, [b[0]]: b.length}), {});

You could do this by not using the filter() method.您可以通过不使用filter()方法来做到这一点。 There's no need to do this if you maintain an index of all of the keys and their current counts.. and you're already doing that with reduce() :如果您维护所有键及其当前计数的索引,则无需执行此操作..并且您已经使用reduce()这样做了:

    let charCount = str => 
        return str.split('').reduce(
            (acc, nextChar) => {
                return {
                    ...acc,
                    [nextChar]: (acc[nextChar] || 0) + 1
                };
            },
            Object.create(null)
        );
    };

This should be O(n) - We only iterate the array twice.这应该是O(n) - 我们只迭代数组两次。 Notice how we do not need to filter() the results because all we need to do is take the existing count for that character in the accumulator and increment it by one.注意我们如何不需要filter()结果,因为我们需要做的就是获取累加器中该字符的现有计数并将其加一。

The usage of Object.create(null) is to create a new object with a null prototype - that means we don't need to use hasOwnProperty() . Object.create(null)的用法是创建一个具有null原型的新对象——这意味着我们不需要使用hasOwnProperty()

You should keep in mind that just because something is O(n^2) does not mean there is a performance problem.您应该记住,仅仅因为O(n^2)并不意味着存在性能问题。 Big O notation just describes how some code will behave as the input data increases. Big O 表示法只是描述了一些代码在输入数据增加时的行为方式。 Only look to optimize code when you know it's a problem.只有当你知道这是一个问题时才去优化代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM