在Javascript中使一个函数应对另一个

时间:2022-07-06 20:44:01

I have two function that filter an array of strings. The first function filters it according to length and the other function according to the char it contains.

我有两个过滤字符串数组的函数。第一个函数根据长度过滤它,另一个函数根据它包含的char来过滤它。

The array of string is loaded on page load.

字符串数组在页面加载时加载。

How to make this functions work together, so when I filter the array according to the char it contains, and I have the appropriate strings, later on I should press the min value, and it should show me the remaining strings from the previous filter. I don't want to load the array again.

如何使这个函数一起工作,所以当我根据它包含的char过滤数组时,我有相应的字符串,稍后我应该按下最小值,它应该显示前一个过滤器的剩余字符串。我不想再次加载数组。

Here I have the first function http://jsfiddle.net/arunpjohny/03avr1vh/2/

这里我有第一个函数http://jsfiddle.net/arunpjohny/03avr1vh/2/

How to add the other and make them work together .

如何添加另一个并使它们一起工作。

Myscript:

function filter() {
    var a = document.getElementById('A').checked,
        e = document.getElementById('E').checked,
        o = document.getElementById('O').checked,
        result2; //make a copy

    result2 = animals.filter(function (value) {
        value = value.toLowerCase();
        return (!a || value.indexOf('a') == -1) && (!e || value.indexOf('e') == -1) && (!o || value.indexOf('o') == -1);
    })
    document.getElementById("demo").innerHTML = result2;
}
filter();

3 个解决方案

#1


jsfiddle demo

After you have a little FP lib built up for yourself, you can write your filter in a declarative way

在为自己构建了一个FP lib后,可以以声明方式编写过滤器

var animals = ["Bear", "Mouse", "Cat", "Tiger", "Lion"];

var letters = ["A", "E", "O"];

function showAnimals() {

    var getSwitches = compose([
        map(prop("value")),
        filter(prop("checked")),
        map(getElementById)
    ]);

    var switches = getSwitches(letters);

    var _filter = compose([
        map(join("")),
        filter(compose([
            not,
            any(flip(elem)(switches)),
            map(toUpperCase)
        ])),
        map(split(""))
    ]);

    var result = _filter(animals);
    getElementById("demo").innerHTML = join(", ")(result);
};

Your two main actions are:

你的两个主要行动是:

  1. getting the checked inputs, converting that to an array of strings.
  2. 获取已检查的输入,将其转换为字符串数组。

  3. filtering the animals based on the checked inputs
  4. 根据检查的输入过滤动物

Each one reads like a little story: (note to read the compose blocks in reverse).

每一个读起来都像一个小故事:(注意反向阅读组合块)。

getSwitches

  1. call getElementById on each of letters
  2. 在每个字母上调用getElementById

  3. filter out the unchecked inputs
  4. 过滤掉未经检查的输入

  5. get the value for each input
  6. 获取每个输入的值

  7. store the resulting array as switches
  8. 将生成的数组存储为开关

_filter

  1. split each animal name into an array of letters
  2. 将每个动物名称分成一组字母

  3. filter each animal by
    • convert animal to uppercase
    • 将动物转换为大写

    • animal should not match any of switches
    • 动物不应该匹配任何开关

  4. 通过将动物转换为大写动物来过滤每只动物不应该与任何开关相匹配

  5. rejoin each animal name to a string
  6. 将每个动物名称重新加入字符串

  7. store the resulting array as result
  8. 将结果数组存储为结果


OK, so that's a lot of functions we used. I'm not going to go into each one in detail, but most FP libs would provide these basics for you. I go into some length detail with building some of these from scratch in this post about function composition.

好的,这就是我们使用的很多功能。我不打算详细介绍每一个,但大多数FP库都会为您提供这些基础知识。我在这篇关于功能构成的帖子中从头开始构建其中的一些,我会详细介绍一些细节。

Before we go further!

在我们走得更远之前!

"Is it performant?"

“它是高效的吗?”

Yup, but compared to what? If you write a single map or filter lambda, you'll likely be able to process the same information a lot faster.

是的,但相比什么?如果您编写单个映射或过滤lambda,您可能能够更快地处理相同的信息。

"So this is slow?"

“所以这很慢?”

Nope, but only you can be the judge of that. It's still going to arrive at the answer in a tiny fraction of a second, so it's plenty fast for me.

不,但只有你可以判断。它仍然会在很短的一秒钟内得出答案,所以它对我来说很快。

"Why is this better?"

“为什么这样更好?”

Well for one, it's a lot more declarative. That is, we're telling the computer what we want, and not necessarily telling it how to give us the answer. The latter is a more imperative style.

好吧,一个,它是更多的声明。也就是说,我们告诉计算机我们想要什么,而不一定告诉它如何给我们答案。后者是一种更为迫切的风格。

Things like setting variables, calling for-loops, etc, are telling the computer how to do it's job. Imperative style isn't bad, it's just it can be bad when it gets overly verbose.

像设置变量,调用for循环等等,正在告诉计算机如何完成它的工作。势在必行的风格也不错,只是当它变得过于冗长时才会变坏。

Notice we were able to solve the problem by defining two variables: switches and result. Everything else is just a function.

请注意,我们可以通过定义两个变量来解决问题:switch和result。其他一切都只是一个功能。

For more information, I encourage you to read the other SO answer I linked above.

有关详细信息,我建议您阅读上面链接的其他SO答案。

For those of you interested, here's the functions I used to make the above solution work

对于那些感兴趣的人,这里是我用来使上述解决方案工作的功能

var id = function(x) {
    return x;
};

var getElementById = function(x) {
    return document.getElementById(x);
};

var neq = function(y) {
    return function(x) {
        return x !== y;
    };
};

var not = function(x) { return !x; };

var prop = function(x) {
    return function(elem) {
        return elem[x];
    };
};

var indexOf = function(y) {
    return function(x) {
        return x.indexOf(y);
    };
};

var elem = function(y) {
    return compose([neq(-1), indexOf(y)]);
};

var map = function(f) {
    return function(xs) {
        return xs.map(f);
    };
};

var filter = function(f) {
    return function(xs) {
        return xs.filter(f);
    };
};

var any = function(f) {
    return function(xs) {
        return xs.some(f);
    }
};

var reduceRight = function(f) {
    return function(i) {
        return function(xs) {
            return xs.reduceRight(uncurry(f), i);
        };
    };
};

var toUpperCase = function(s) {
    return s.toUpperCase();
};

var split = function(y) {
    return function(x) {
        return x.split(y);
    };
};

var join = function(y) {
    return function(x) {
        return x.join(y);
    };
};

var flip = function(f) {
    return function(y) {
        return function(x) {
            return f(x)(y);
        };
    };
};

var uncurry = function(f) {
    return function(x, y) {
        return f(x)(y);
    };
};

var compose = flip(reduceRight(flip(id)));

And that's all, Folks!

这就是全部,伙计们!

#2


You can chain the length filter after the letter filter:

您可以在字母过滤器后链接长度过滤器:

result2 = animals.filter(function (value) {
    // letter filter
}).filter(function (value) {
    // length filter
});

A quick sample.

快速样本。

#3


or you can use some functional programming and do a curry of two functions like this:

或者您可以使用一些函数式编程并执行两个函数的咖喱:

function compose(f1, f2)
{
   return function(val) {
      return f1(val)&&f2(val);
   }
}
// in this case the .filter traverses the array only once, 
// instead of twice, i.e once for each subfilter function
result2 = animals.filter(compose(letterFilter, lengthFilter));

jsfiddle example

UPDATE if in understand correctly and you need to filter again (by another filter) at a later time, you will need to store the intermediate results from previous filter and use these as input to the other filter, or just filter the whole array again with a composed filter (as in this example).

更新如果正确理解并且您需要稍后再次过滤(通过另一个过滤器),则需要存储前一过滤器的中间结果并将其用作另一个过滤器的输入,或者仅使用过滤器重新过滤整个数组组合过滤器(如本例所示)。

The best approach depends on the size of the array and code modularity and independence you would like to achieve.

最好的方法取决于数组的大小和代码模块性以及您希望实现的独立性。

#1


jsfiddle demo

After you have a little FP lib built up for yourself, you can write your filter in a declarative way

在为自己构建了一个FP lib后,可以以声明方式编写过滤器

var animals = ["Bear", "Mouse", "Cat", "Tiger", "Lion"];

var letters = ["A", "E", "O"];

function showAnimals() {

    var getSwitches = compose([
        map(prop("value")),
        filter(prop("checked")),
        map(getElementById)
    ]);

    var switches = getSwitches(letters);

    var _filter = compose([
        map(join("")),
        filter(compose([
            not,
            any(flip(elem)(switches)),
            map(toUpperCase)
        ])),
        map(split(""))
    ]);

    var result = _filter(animals);
    getElementById("demo").innerHTML = join(", ")(result);
};

Your two main actions are:

你的两个主要行动是:

  1. getting the checked inputs, converting that to an array of strings.
  2. 获取已检查的输入,将其转换为字符串数组。

  3. filtering the animals based on the checked inputs
  4. 根据检查的输入过滤动物

Each one reads like a little story: (note to read the compose blocks in reverse).

每一个读起来都像一个小故事:(注意反向阅读组合块)。

getSwitches

  1. call getElementById on each of letters
  2. 在每个字母上调用getElementById

  3. filter out the unchecked inputs
  4. 过滤掉未经检查的输入

  5. get the value for each input
  6. 获取每个输入的值

  7. store the resulting array as switches
  8. 将生成的数组存储为开关

_filter

  1. split each animal name into an array of letters
  2. 将每个动物名称分成一组字母

  3. filter each animal by
    • convert animal to uppercase
    • 将动物转换为大写

    • animal should not match any of switches
    • 动物不应该匹配任何开关

  4. 通过将动物转换为大写动物来过滤每只动物不应该与任何开关相匹配

  5. rejoin each animal name to a string
  6. 将每个动物名称重新加入字符串

  7. store the resulting array as result
  8. 将结果数组存储为结果


OK, so that's a lot of functions we used. I'm not going to go into each one in detail, but most FP libs would provide these basics for you. I go into some length detail with building some of these from scratch in this post about function composition.

好的,这就是我们使用的很多功能。我不打算详细介绍每一个,但大多数FP库都会为您提供这些基础知识。我在这篇关于功能构成的帖子中从头开始构建其中的一些,我会详细介绍一些细节。

Before we go further!

在我们走得更远之前!

"Is it performant?"

“它是高效的吗?”

Yup, but compared to what? If you write a single map or filter lambda, you'll likely be able to process the same information a lot faster.

是的,但相比什么?如果您编写单个映射或过滤lambda,您可能能够更快地处理相同的信息。

"So this is slow?"

“所以这很慢?”

Nope, but only you can be the judge of that. It's still going to arrive at the answer in a tiny fraction of a second, so it's plenty fast for me.

不,但只有你可以判断。它仍然会在很短的一秒钟内得出答案,所以它对我来说很快。

"Why is this better?"

“为什么这样更好?”

Well for one, it's a lot more declarative. That is, we're telling the computer what we want, and not necessarily telling it how to give us the answer. The latter is a more imperative style.

好吧,一个,它是更多的声明。也就是说,我们告诉计算机我们想要什么,而不一定告诉它如何给我们答案。后者是一种更为迫切的风格。

Things like setting variables, calling for-loops, etc, are telling the computer how to do it's job. Imperative style isn't bad, it's just it can be bad when it gets overly verbose.

像设置变量,调用for循环等等,正在告诉计算机如何完成它的工作。势在必行的风格也不错,只是当它变得过于冗长时才会变坏。

Notice we were able to solve the problem by defining two variables: switches and result. Everything else is just a function.

请注意,我们可以通过定义两个变量来解决问题:switch和result。其他一切都只是一个功能。

For more information, I encourage you to read the other SO answer I linked above.

有关详细信息,我建议您阅读上面链接的其他SO答案。

For those of you interested, here's the functions I used to make the above solution work

对于那些感兴趣的人,这里是我用来使上述解决方案工作的功能

var id = function(x) {
    return x;
};

var getElementById = function(x) {
    return document.getElementById(x);
};

var neq = function(y) {
    return function(x) {
        return x !== y;
    };
};

var not = function(x) { return !x; };

var prop = function(x) {
    return function(elem) {
        return elem[x];
    };
};

var indexOf = function(y) {
    return function(x) {
        return x.indexOf(y);
    };
};

var elem = function(y) {
    return compose([neq(-1), indexOf(y)]);
};

var map = function(f) {
    return function(xs) {
        return xs.map(f);
    };
};

var filter = function(f) {
    return function(xs) {
        return xs.filter(f);
    };
};

var any = function(f) {
    return function(xs) {
        return xs.some(f);
    }
};

var reduceRight = function(f) {
    return function(i) {
        return function(xs) {
            return xs.reduceRight(uncurry(f), i);
        };
    };
};

var toUpperCase = function(s) {
    return s.toUpperCase();
};

var split = function(y) {
    return function(x) {
        return x.split(y);
    };
};

var join = function(y) {
    return function(x) {
        return x.join(y);
    };
};

var flip = function(f) {
    return function(y) {
        return function(x) {
            return f(x)(y);
        };
    };
};

var uncurry = function(f) {
    return function(x, y) {
        return f(x)(y);
    };
};

var compose = flip(reduceRight(flip(id)));

And that's all, Folks!

这就是全部,伙计们!

#2


You can chain the length filter after the letter filter:

您可以在字母过滤器后链接长度过滤器:

result2 = animals.filter(function (value) {
    // letter filter
}).filter(function (value) {
    // length filter
});

A quick sample.

快速样本。

#3


or you can use some functional programming and do a curry of two functions like this:

或者您可以使用一些函数式编程并执行两个函数的咖喱:

function compose(f1, f2)
{
   return function(val) {
      return f1(val)&&f2(val);
   }
}
// in this case the .filter traverses the array only once, 
// instead of twice, i.e once for each subfilter function
result2 = animals.filter(compose(letterFilter, lengthFilter));

jsfiddle example

UPDATE if in understand correctly and you need to filter again (by another filter) at a later time, you will need to store the intermediate results from previous filter and use these as input to the other filter, or just filter the whole array again with a composed filter (as in this example).

更新如果正确理解并且您需要稍后再次过滤(通过另一个过滤器),则需要存储前一过滤器的中间结果并将其用作另一个过滤器的输入,或者仅使用过滤器重新过滤整个数组组合过滤器(如本例所示)。

The best approach depends on the size of the array and code modularity and independence you would like to achieve.

最好的方法取决于数组的大小和代码模块性以及您希望实现的独立性。