博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何在JavaScript中使用map(),filter()和reduce()
阅读量:2507 次
发布时间:2019-05-11

本文共 22586 字,大约阅读时间需要 75 分钟。

介绍 (Introduction)

Functional programming in JavaScript benefits code readability, maintainability, and testability.

JavaScript中的函数式编程可提高代码的可读性,可维护性和可测试性。

One of tools from the functional programming mindset is programming in an array-processing style. This entails taking arrays as your fundamental data structure. Then, your program becomes a series of operations on elements in the array.

功能编程思维方式中的一种工具是以数组处理方式进行编程。 这需要将数组作为基本数据结构。 然后,您的程序将对数组中的元素进行一系列操作。

There are many contexts in which this is useful, such as , removing extraneous data with filter, and using reduce. These functions, called “Array Extras”, are abstractions over for loops. There is nothing you can do with with these functions that you can’t achieve with for, and vice-versa.

在许多情况下这很有用,例如使用filter删除无关的数据以及使用reduce 。 这些函数称为“ Array Extras”,是for循环的抽象。 这些功能对for是无能为力的,反之亦然。

In this tutorial, we’ll develop a deeper understanding of functional programming in JavaScript by taking a look at filter, map, and reduce.

在本教程中,我们将通过查看filtermapreduce加深对JavaScript函数编程的了解。

for迭代 (Iteration with for)

We use for loops to iterate over every item in an array. Usually, we do something to each item along the way.

我们使用for循环来遍历数组中的每个项目。 通常,我们会在此过程中对每个项目进行处理。

One example would be capitalizing every string in an array.

一个示例是将数组中的每个字符串都大写。

const strings = ['arielle', 'are', 'you', 'there'];const capitalizedStrings = [];for (let i = 0; i < strings.length; i += 1) {    const string = strings[i];    capitalizedStrings.push(string.toUpperCase());}console.log(capitalizedStrings);

In this snippet, we start with an array of lowercase names. Then, we initialize an empty array, in which we’ll store our capitalized strings.

在此代码段中,我们从一个小写名称数组开始。 然后,我们初始化一个空数组,在其中存储大写的字符串。

Inside of the for loop, we grab the next string on every iteration; capitalize it; and push it into capitalizedStrings. At the end of the loop, capitalizedStrings contains every word in strings, but…You know, capitalized.

for循环内,每次迭代都获取下一个字符串; 大写; 并将其推送到capitalizedStrings 。 在循环的最后, capitalizedStrings strings包含strings中的每个单词,但是…,大写。

This brings us to our first function: . This is a method on arrays that “automatically” loops through the list for us. In other words, it handles the details of initializing and incrementing a counter for us.

这将我们带到我们的第一个功能: 。 这是对阵列的一种方法,可为我们“自动”遍历列表。 换句话说,它我们处理初始化和递增计数器的细节。

Instead of the above, where we manually index into strings, we can call forEach, and receive the next string on every iteration. The updated version would look something like:

代替上面的方法,我们在其中手动索引为strings ,我们可以调用forEach ,并在每次迭代时接收下一个字符串。 更新后的版本如下所示:

const strings = ['arielle', 'are', 'you', 'there'];const capitalizedStrings = [];strings.forEach(function (string) {    capitalizedStrings.push(string.toUpperCase());})

This is almost the same as what we started with. But getting rid of that i makes our code more readable.

这与我们开始时几乎相同。 但摆脱那i让我们的代码更易读。

This also introduces a major pattern we’ll see time and time again. Namely: We prefer to use methods on Array.prototype that abstract away details like initializing and incrementing counters. That way, we can focus on the important logic, rather than the boilerplate.

这也引入了一种主要模式,我们将一次又一次看到。 即:我们更喜欢在Array.prototype上使用抽象化细节的方法,例如初始化和递增计数器。 这样,我们可以专注于重要的逻辑,而不是样板。

了解凯撒密码和蛮力 (Understanding the Caesar Cipher and Brute Force)

In the snippets below, we’ll use encrypting and decrypting strings in our examples of map, reduce, and filter.

在下面的代码片段中,我们将在mapreducefilter示例中使用加密和解密字符串。

For example:

例如:

// Thanks to EvanHahn for this: https://gist.github.com/EvanHahn/2587465const caesar = require('./caesar');// We can encrypt the string: 'this is my secret message' with `caesar`// Here, we scramble the message by shifting each letter forward by 2 letters: 'a' becomes 'c'; 's' becomes  'u'; etc.const encryptedString = caesar('this is my super secret message.', 2);console.log(encryptedString); // 'vjku ku oa uwrgt ugetgv uvtkpi.'

The idea is that, if I send you a normal message, like 'this is my super secret message', and someone else gets their hands on it, they can read the secret immediately. This obviously sucks if you’re sending sensitive information, like passwords, which someone might be listening for.

这个想法是,如果我向您发送一条普通消息,例如'this is my super secret message' ,并且有人得到了帮助,他们可以立即读取该机密。 如果您正在发送敏感信息(例如密码),而有人可能正在监听这些信息,这显然很糟糕。

Encrypting a string means: “scrambling it to make it hard to read without unscrambling.” This way, even if someone is listening, and even if they do intercept your message, it will remain unreadable until they unscramble it. To quote the example above, it’s pretty non-obvious what the string 'vjku ku oa uwrgt ugetgv uvtkpi.' is supposed to mean.

加密字符串的意思是:“对其进行加扰使其难以阅读而不加扰。” 这样,即使有人听,并且即使他们确实拦截了您的消息,消息也将保持不可读状态,直到他们对其进行解密。 引用上面的示例,字符串'vjku ku oa uwrgt ugetgv uvtkpi.' 应该是这个意思。

The is one way to scramble a string like this. To encrypt with the Caesar cipher, we pick a key, n, between 1 and 24, and replace every letter in the original string with the one n letters further down the alphabet.

是一种这样的字符串的方法。 要使用Caesar密码进行加密,我们选择一个介于1和24之间的密钥 n ,并将原始字符串中的每个字母替换为字母表后面的n个字母。

So, if we choose the key 2, a becomes c; b becomes d; c becomes e; etc.

因此,如果我们选择键2,则a变为cb变成d ; c变成e ; 等等

Substituting letters like this makes the original string pretty unreadable. But, we scrambled by shifting letters. So, all you need to do to unscramble is shift them back. If you get a message you know was encrypted with the key 2, all you need to do to decrypt is shift letters back two spaces. So, c becomes a; d becomes b; etc.

像这样替换字母会使原始字符串难以理解。 但是,我们争先恐后地转移了信件。 因此,您要做的所有工作就是将它们移回原位。 如果您收到一条消息,说明您已使用密钥2进行了加密,则解密所需要做的就是将字母向后移两个空格。 因此, c变为ad变成b ; 等等

Unfortunately, this is a not a robust form of encryption today as it’s extremely easy to break. One way to decrypt any string encrypted with a Caesar cipher is to just try to decrypt it with every possible key. One of the results will be correct. All you need to do is scan the array of 24 outputs for the one that’s English. The others will be just as unreadable as the original string.

不幸的是,由于它非常容易破解,因此今天它并不是一种强大的加密形式。 解密使用Caesar密码加密的任何字符串的一种方法是仅尝试使用每个可能的密钥对其进行解密。 其中一个结果是正确的。 您需要做的就是扫描24个输出数组,查找英文输出。 其他的将与原始字符串一样不可读。

Below, I’ll use a function called tryAll, which does just that. Namely: It takes an encrypted string, and returns an array of every possible decryption. One of those results will be the string we want. So, this always breaks the cipher.

在下面,我将使用一个名为tryAll的函数来执行此操作。 即:它接受一个加密的字符串,并返回所有可能解密的数组。 这些结果之一将是我们想要的字符串。 因此,这总是会破坏密码。

It is challenging to scan an array of 24 possible decryptions. We should be able to eliminate ones that are definitely incorrect.

扫描24种可能的解密阵列具有挑战性。 我们应该能够消除绝对不正确的问题。

In the section on filter, you’ll see a function, called isEnglish, which does just this. In particular, it reads a string; counts how many of the most common 1,000 words in English occur in that string; and, if it finds more than 3 of those words in the sentence, it classifies the string as English. If the string contains fewer than 3 words from that array, it throws it out.

filter的部分中,您将看到一个名为isEnglish的函数,该函数就是这样做的。 特别是,它读取一个字符串。 计算该字符串中英语中最常见的1,000个单词中有多少个; 并且,如果在句子中找到三个以上的单词,则将该字符串分类为英语。 如果该字符串中包含少于3个单词,则将其丢弃。

There are more sophisticated ways to check if a string is English, of course, but this is fine for now.

当然,还有更复杂的方法来检查字符串是否为英语,但这目前还可以。

The implementations of tryAll and isEnglish aren’t important, but if you’re curious, you can find them at this gist: .

tryAllisEnglish的实现并不重要,但是如果您好奇的话,可以在以下要点找到它们: 。

使用map转换数组 (Transforming Arrays with map)

Refactoring a for loop to use forEach hints at advantages of this style. But there’s still room for improvement in the updated version.

重构for循环以使用forEach暗示这种样式的优点。 但是更新版本仍有改进的空间。

In the example above, we’re updating capitalizedStrings within the callback to forEach. There’s nothing inherently wrong with this. But, it saves a lot of headache to avoid side effects like that whenever possible.

在上面的示例中,我们将回调内的capitalizedStrings更新为forEach 。 这天生没有错。 但是 ,它避免了很多可能的副作用,从而避免了很多麻烦。

If we don’t have to update data structures that live in a different scope…We probably shouldn’t.

如果我们没有生活在不同的范围内更新数据结构......我们也许不应该。

In this particular case, we wanted to turn every string in strings into its capitalized version. This is a very common use case for a for loop: Take everything in an array; turn it into something else; and collect the results in a new array.

在这种特殊情况下,我们希望把每串strings到它的大写版本。 这是for循环的一个非常常见的用例:将所有内容放在一个数组中; 把它变成别的东西; 并将结果收集到一个新数组中。

Transforming every element in an array into a new one and collecting the results is called mapping. JavaScript has a built-in function for just this use case, called, appropriately enough, .

将数组中的每个元素转换为新元素并收集结果称为映射 。 JavaScript为此用途提供了一个内置函数,即适当地称为 。

We used forEach because it abstracts away the need to manage the iteration variable, i. We don’t have to manually index into the array, etc., and so we can focus on the logic that really matters.

之所以使用forEach是因为它抽象出了管理迭代变量i 。 我们不必手动索引到数组等中,因此我们可以专注于真正重要的逻辑。

Similarly, we use map because it abstracts away initializing an empty array, and pushing to it. Just like forEach accepts a callback that does something with each string value, map accepts a callback that does something with each string value.

类似地,我们使用map因为它抽象了初始化一个空数组并将其推送到它的过程。 就像forEach接受对每个字符串值执行某些操作的回调一样, map接受对每个字符串值执行某些操作的回调。

Let’s look at a quick demo before a final explanation. In this example, I’m using a function to “encrypt” an array of messages. We could use a for loop, and we could use forEach…But, it’s better with map.

在进行最终解释之前,让我们看一下快速演示。 在此示例中,我使用一个函数来“加密”消息数组。 我们可以使用for循环,也可以使用forEach …但是,使用map更好。

const caesar = require('../caesar');const key = 12;const messages = [    'arielle, are you there?',    'the ghost has killed the shell',    'the liziorati attack at dawn']const encryptedMessages = messages.map(function (string) {    return caesar(string, key);})console.log(encryptedMessages);

Note what happened here.

注意这里发生了什么。

  • We start with an array of messages, in plain English.

    我们从简单的英语messages开始。

  • We use the map method on messages to encrypt each string with the caesar function, and automagically store the result in a new array.

    我们对messages使用map方法,通过caesar函数对每个字符串进行加密,然后自动将结果存储在新数组中。

After the above code runs, encryptedMessages looks like: ['mduqxxq, mdq kag ftqdq?', 'ftq staef tme wuxxqp ftq etqxx', 'ftq xuluadmfu mffmow mf pmiz'].

上面的代码运行之后, encryptedMessages看起来像: ['mduqxxq, mdq kag ftqdq?', 'ftq staef tme wuxxqp ftq etqxx', 'ftq xuluadmfu mffmow mf pmiz']

This is a much higher level of abstraction than manually pushing to an array.

这比手动推送到数组要高得多。

Now is a good time to point out that we can use arrow functions to express this sort of thing more concisely:

现在是指出我们可以使用箭头函数更简洁地表达这种事情的好时机:

const caesar = require('../caesar');const key = 12;const messages = [    'arielle, are you there?',    'the ghost has killed the shell',    'the liziorati attack at dawn'];const encryptedMessages = messages.map(string => string.toUpperCase()):console.log(encryptedMessages);

filter扔东西 (Throwing Things Away with filter)

Another common pattern is using a for loop to process items in an array, but only pushing/preserving some of them.

另一个常见的模式是使用for循环来处理数组中的项目,但仅推送/保留其中的一些项目。

We usually decide which items to keep, and which to throw away, by doing an if check.

我们通常通过进行if检查来决定保留哪些物品,丢弃哪些物品。

In raw JS, this might look like:

在原始JS中,这可能类似于:

// Secret message! This was a string encrypted with a key between 1 and 24.const encryptedMessage = 'mduqxxq, mdq kag ftqdq?'];// We can break this code by just decrypting with _every_ possible key.const possibilities = tryAll(encryptedMessage);// Most of these decryption attempts aren't readable. Sad.// We can speed up finding the ones that are probably junk with an if checkconst likelyPossibilities = [];possibilities.forEach(function (decryptionAttempt) {    // Keep the string if it looks like an English sentence    if (isEnglish(decryptionAttempt)) {        likelyPossibilities.push(decryptionAttempt);    }})

First, we try to decrypt the encrypted message with every possible key. That means we end up with an array of 24 possibilities.

首先,我们尝试使用所有可能的密钥解密加密的消息。 这意味着我们最终有24种可能性。

In this loop, we test each one to see if it looks like an English string. If so, we keep it. If not, we throw it away.

在这个循环中,我们测试每个人是否看起来像一个英语字符串。 如果是这样,我们保留它。 如果没有,我们将其丢弃。

This is clearly a common use case. So, there’s a built-in for it, aptly named .

显然,这是一个常见的用例。 因此,有一个内置的名称,恰当地命名为 。

As with map, we pass filter a callback, which also gets each string. The difference is that, filter will only save items in an array if the callback returns true. So, we could express the above as:

map ,我们通过filter回调,该回调也获取每个字符串。 区别在于,仅当回调返回true时, filter才会将项目保存在数组中。 因此,我们可以将以上内容表达为:

// Secret message! This was a string encrypted with a key between 1 and 24.const encryptedMessage = 'mduqxxq, mdq kag ftqdq?'];// We can break this code by just decrypting with _every_ possible key.const possibilities = tryAll(encryptedMessage);// Most of these decryption attempts aren't readable. Sad.// We can speed up finding the ones that are probably junk with an if checkconst likelyPossibilities = possibilities.filter(function (string) {    // If isEnglish(string) returns true, filter saves in the output array    return isEnglish(string);})

Since this callback just calls isEnglish, we could actually write it even more concisely, like this:

由于此回调仅调用isEnglish ,因此实际上我们可以更简洁地编写它,如下所示:

// Secret message! This was a string encrypted with a key between 1 and 24.const encryptedMessage = 'mduqxxq, mdq kag ftqdq?'];// We can break this code by just decrypting with _every_ possible key.const possibilities = tryAll(encryptedMessage);// Most of these decryption attempts aren't readable. Sad.// We can speed up finding the ones that are probably junk with an if checkconst likelyPossibilities = possibilities.filter(isEnglish);

reduce负担 (Bringing Things Together with reduce)

So far, we’ve seen abstractions for three common use cases around arrays:

到目前为止,我们已经看到了数组中三个常见用例的抽象:

  • forEach, which allows us to iterate over an array as with for, but eliminates the need to manually manage the iteration variable i; index into the array; etc.

    forEach ,它允许我们像for一样遍历数组,但是不需要手动管理迭代变量i ; 索引到数组; 等等

  • map, which lets us transform each element of an array, and collect the results in an array

    map ,它使我们可以变换数组的每个元素,并将结果收集到数组中

  • filter, which lets us choose which elements of an array to keep

    filter ,它使我们可以选择保留数组的哪些元素

Another common use case is: Iterating over an array to collect its elements into a single result.

另一个常见的用例是:遍历数组以其元素收集到单个结果中。

The prototypical example is adding up a bunch of numbers.

典型的例子是将一堆数字相加。

// prices of: (big) box of oreos, girl scout cookies, fidget spinner, gold-plated Arch linux magnetconst prices = [12, 19, 7, 209];// variable to store our total prices inlet totalPrice = 0;for (let i = 0; i < prices.length; i += 1) {    totalPrice += prices[i];}// Report our total prices: $247console.log(`Your total is ${totalPrice}.`);

As I’m sure you’d guess, there’s an abstraction for this, too: .

就像您确定的那样,我也对此有一个抽象: 。

Refactoring the above loop with reduce looks like:

reduce重构上述循环看起来像:

const prices = [12, 19, 7, 209];prices.reduce(function (totalPrice, nextPrice) {    // totalPrice is the price so far    console.log(`Total price so far: ${totalPrice}`)    console.log(`Next price to add: ${nextPrice}`)    // update totalPrice by adding the next price    totalPrice += nextPrice    // return the total price, and start over again    return totalPrice}, 0)// ^ the second argument to `reduce` is the totalPrice to start with on the first iteration

Like map and filter, reduce accepts a callback, which it runs on each element of the array.

mapfilter一样, reduce接受一个回调,它在数组的每个元素上运行。

Unlike map and filter, the callback we pass to reduce accepts two arguments: a totalPrice, and a nextPrice.

mapfilter不同,我们传递来reduce的回调接受两个参数: totalPricenextPrice

totalPrice is like total in the first example: It’s the price we’ve gotten by adding up all the prices we’ve seen so far.

totalPrice在第一个示例中类似于total :这是我们将到目前为止所看到的所有价格相加得到的价格。

nextPrice is the number we got by doing prices[i] in the first example. Recall that map and reduce automatically index into the array for us, and pass this value to their callbacks automatically. reduce does the same thing, but passes that value as the second argument to its callback.

nextPrice是第一个示例中通过prices[i]得到的数字。 回忆一下该map并为我们自动reduce到数组的索引,然后将此值自动传递给其回调。 reduce做同样的事情,但是将该值作为第二个参数传递给其回调。

Just like with map and reduce, on each iteration, we have to return the value we’re interested in getting back at the end of the loop. Namely, totalPrice.

就像mapreduce ,在每次迭代中,我们都必须在循环结束时返回我们想要返回的值。 即totalPrice

Finally, note that we pass another argument after the callback to reduce. In this case, we pass 0. This is analogous to the line in the first example where we set const total = 0. That second argument is the initial value of totalPrice.

最后,请注意,我们在回调后传递另一个参数reduce 。 在这种情况下,我们传递0 。 这类似于第一个示例中的行,其中我们设置const total = 0 。 第二个参数是totalPrice的初始值。



reduce is harder to grok than map or filter, so let’s take a look at another example.

reducemapfilter难理解,所以让我们看另一个例子。

In the previous example, we used reduce to collect an array of numbers into a sum. But reduce is versatile. We can use it to turn an array into a any single result.

在前面的示例中,我们使用reduce来将数字数组收集为一个和。 但是reduce是通用的。 我们可以使用它将数组转换为任何单个结果。

For example, we can use it to build up a string.

例如,我们可以使用它来构建一个字符串。

const courses = ['Introduction to Programming', 'Algorithms & Data Structures', 'Discrete Math'];const curriculum = courses.reduce(function (courseList, course) {    // add the name to the class, with a preceding newline and tab for indentation    return courseList += `\n\t${course}`;}, 'The Computer Science curriculum consists of:');console.log(curriculum);

This generates the output:

生成输出:

The Computer Science curriculum consists of:    Introduction to Programming    Algorithms & Data Structures    Discrete Math

I don’t see a ton of examples of using reduce to build strings like this, for some reason, but it’s common practice in a functional style.

由于某种原因,我没有看到很多使用reduce来构建这样的字符串的示例,但这是功能样式的常见做法。



Again, reduce is versatile: We can use it to turn an array into any kind of “single” result.

同样, reduce是通用的:我们可以使用它将数组转换为任何类型的“单个”结果。

Even if that single result is another array.

即使单个结果是另一个数组。

Check it:

核实:

const names = ['arielle', 'jung', 'scheherazade'];const titleCase = function (name) {    // uppercase first letter of name    const first = name[0];    const capitalizedFirst = first.toUpperCase();    // get rest of name    const rest = name.slice(1);    // create list with all letters of the name, including capitalized first letter    const letters = [capitalizedFirst].concat(rest);    // join letters, return result    return letters.join('');}const titleCased = names.reduce(function (titleCasedNames, name) {    // title-case the next name    const titleCasedName = titleCase(name);    // add the title-cased name to a list    titleCasedNames.push(titleCasedName);    // return list of capitalizedNames    return titleCasedNames}, [])// ^ start with an empty listconsole.log(titleCased);// ["Arielle", "Jung", "Scheherazade"]

So…This is neat. We used reduce to turn a list of lower-cased names into a list of title-cased names.

所以...这很干净。 我们使用reduce将一个小写名称列表转换为一个标题大写名称列表。

Previously, we turned a list of numbers into a single sum, and a list of strings into a single string. Here, we turned a list of names into a single list of title-case names.

以前,我们将数字列表转换为单个和,将字符串列表转换为单个字符串。 在这里,我们将名称列表变成了标题大小写名称的单个列表。

This is still allowed, because the single list of title-cased names is still a single result. It just happens to be a collection, rather than a primitive type.

仍然允许这样做,因为标题大小写名称的单个列表仍然是单个结果。 它只是一个集合,而不是原始类型。



You might have noticed something about that last example: We used reduce for the same task that we used map for earlier.

您可能已经注意到了关于最后一个示例的一些信息:对于与之前使用map相同的任务,我们使用了reduce

It might not be obvious, yet, but—this is a big deal.

可能还不很明显,但是- 这很重要

You might guess that we can write map in terms of reduce. You’d be right.

您可能会猜想我们可以根据reduce编写map 。 没错

const map = (list, mapFunction) => {    const output = list.reduce((transformedList, nextElement) => {        // use the mapFunction to transform the nextElement in the list         const transformedElement = mapFunction(nextElement);        // add transformedElement to our list of transformed elements        transformedList.push(transformedElement);        // return list of transformed elements        return transformedList;    }, [])    // ^ start with an empty list    return output;}

We can get the same result as above with:

我们可以通过以下方法获得与上述相同的结果:

// congratulations...you just implemented `map` with `reduce`. badass.const titleCased = map(names, titleCase);console.log(titleCased);// ["Arielle", "Jung", "Scheherazade"]

Obligatory disclaimer: If you were actually implementing a production-ready map, you’d need to add some features to this implementation. We’ll leave all that off in the interest of clarity.

强制性免责声明:如果您实际上是在实现生产就绪map ,则需要在此实现中添加一些功能。 为了清楚起见,我们将忽略所有这些内容。



If we can use reduce to implement map, what about filter?

如果我们可以使用reduce来实现map ,那么filter呢?

const filter = (list, predicate) => {    const output = list.reduce(function (filteredElements, nextElement) {        // only add `nextElement` if it passes our test        if (predicate(nextElement)) {            filteredElements.push(nextElement);        }        // return the list of filtered elements on each iteration        return filteredElements;        }, [])    })}

We’d use this like:

我们将这样使用:

 

It’s alright if this one feels confusing. It’s a new idea even for more experienced developers. But, it’s worth the work to wrap your head around it: We’ll need this little bit of insight to make sense of transduction a little bit later.

如果这让人感到困惑,那也没关系。 即使对于经验丰富的开发人员来说,这也是一个新想法。 但是,值得您全神贯注的工作是:我们需要一点点洞察力,以便稍后再进行转导。

…And, trust me, transduction alone is cool enough to be worth the work.

…而且,请相信我,仅转导就足够了,值得进行这项工作。

结论 (Conclusion)

In this tutorial, you’ve learned how to use map, filter, and reduce to write more readable code.

在本教程中,您学习了如何使用mapfilterreduce编写更具可读性的代码。

Not, of course, that there’s anything wrong with using for. But raising the level of abstraction with these functions brings immediate benefits to readability and maintainability, by corollary.

当然,使用for不会有任何问题。 但是,通过这些功能来提高抽象级别将直接带来可读性和可维护性的好处。

From here, you can begin to explore other array methods such asflatten, concat, and flatMap.

从这里开始,您可以开始探索其他数组方法,例如flattenconcatflatMap

翻译自:

转载地址:http://klhgb.baihongyu.com/

你可能感兴趣的文章
VNPY - CTA策略模块策略开发
查看>>
VNPY - 事件引擎
查看>>
MongoDB基本语法和操作入门
查看>>
学习笔记_vnpy实战培训day04_作业
查看>>
OCO订单(委托)
查看>>
学习笔记_vnpy实战培训day06
查看>>
回测引擎代码分析流程图
查看>>
Excel 如何制作时间轴
查看>>
matplotlib绘图跳过时间段的处理方案
查看>>
vnpy学习_04回测评价指标的缺陷
查看>>
iOS开发中遇到的问题整理 (一)
查看>>
Linux(SUSE 12)安装jboss4并实现远程访问
查看>>
Neutron在给虚拟机分配网络时,底层是如何实现的?
查看>>
netfilter/iptables全攻略
查看>>
Overlay之VXLAN架构
查看>>
Eclipse : An error occurred while filtering resources(Maven错误提示)
查看>>
在eclipse上用tomcat部署项目404解决方案
查看>>
web.xml 配置中classpath: 与classpath*:的区别
查看>>
suse如何修改ssh端口为2222?
查看>>
详细理解“>/dev/null 2>&1”
查看>>