为IF编写可变数量的参数 [英] Write a variable number of arguments for IF

查看:81
本文介绍了为IF编写可变数量的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个可以解决此问题的任何常规版本的函数:

I am trying to write a function that would solve any general version of this problem:

如果我们列出所有低于10的自然数,它们是3或5的倍数,则得到3、5、6和9.这些倍数的总和为23.

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

找到1000以下的3或5的所有倍数之和.

Find the sum of all the multiples of 3 or 5 below 1000.

我为此实例解决的方法是:

The way I solved it for this instance was:

multiples = Array(Int, 0)
[ (i % 3 == 0 || i % 5 == 0) && push!(multiples, i) for i in 1:1000 ]
sum(multiples)

我想编写一个函数,该函数将使用多个数组(在本例中为[3,5])和最终数字(在本例中为1000).关键是数组可以由任意多个数字组成,而不仅仅是两个数字(例如[3,5,6]).然后,该函数应为每个N运行i % N == 0.

I want to write a function that will take an array of multiples (in this case, [3,5]) and the final number (in this case, 1000). The point is that the array can consist of arbitrarily many numbers, not just two (e.g., [3,5,6]). Then the function should run i % N == 0 for each N.

我如何最有效地做到这一点?可能涉及元编程吗? (代码不必采用列表理解格式.)

How do I do that most efficiently? Could that involve metaprogramming? (The code doesn't have to be in a list comprehension format.)

谢谢!

推荐答案

使用模除法和函数式样式,出现在我头上的第一件事是

Very first thing that popped into my head was the following, using modulo division and a functional style:

v1(N,M) = sum(filter(k->any(j->k%j==0,M), 1:N))

但是我想研究一些替代方法,因为这有两个问题:

But I wanted to investigate some alternatives, as this has two problems:

  1. 两个级别的匿名功能,Julia尚未很好地进行优化(到目前为止).
  2. 根据范围创建一个临时数组,然后求和.

因此,这是最明显的替代方案,即单衬套的 C样式版本:

So here is the most obvious alternative, the C-style version of the one-liner:

function v2(N,M)
    sum_so_far = 0
    for k in 1:N
        for j in M
            if k%j==0
                sum_so_far += k
                break
            end
        end
    end
    return sum_so_far
end

但是后来我再考虑了一下,记得在某处读到模除法是一个缓慢的操作.我想看看IntSet的表现-专门用于整数的集合.所以这是另一种单行代码, IntSet,不使用任何模块划分,以及一种功能样式!

But then I thought about it some more, and remembered reading somewhere that modulo division is a slow operation. I wanted to see how IntSets perform - a set specialized for integers. So here is another one-liner, IntSets without using any module division, and a functional style!

v3(N,M) = sum(union(map(j->IntSet(j:j:N), M)...))

将地图扩展到for循环中,并将union!重复应用于单个IntSet并没有太大的好处,因此在此不再赘述.要对此进行细分:

Expanding the map into a for loop and repeatedly applying union! to a single IntSet was not much better, so I won't include that here. To break this down:

  • IntSet(j:j:N)是j和N之间j的所有倍数.
  • j->IntSet(j:j:N)是一个匿名函数,返回该IntSet
  • map(j->IntSet(j:j:N), M)将该函数应用于M中的每个j,并返回Vector{IntSet}.
  • ...将向量喷溅"到union
  • 的参数中
  • union创建一个IntSet作为其参数的并集-在这种情况下,为M中所有数字的倍数
  • 然后我们总结一下
  • IntSet(j:j:N) is all the multiples of j between j and N
  • j->IntSet(j:j:N) is an anonymous function that returns that IntSet
  • map(j->IntSet(j:j:N), M) applies that function to each j in M, and returns a Vector{IntSet}.
  • The ... "splats" the vector out into arguments of union
  • union creates an IntSet that is the union of its arguments - in this case, all multiples of the numbers in M
  • Then we sum it to finish

我对这些进行了基准测试

I benchmarked these with

N,M = 10000000, [3,4,5]

为您提供

  • 单线:2.857292874 seconds (826006352 bytes allocated, 10.49% gc time)
  • C风格:0.190581908 seconds (176 bytes allocated)
  • IntSet无模数:0.121820101 seconds (16781040 bytes allocated)
  • One-liner: 2.857292874 seconds (826006352 bytes allocated, 10.49% gc time)
  • C-style: 0.190581908 seconds (176 bytes allocated)
  • IntSet no modulo: 0.121820101 seconds (16781040 bytes allocated)

因此,您绝对可以甚至用更高级别的对象来击败C风格的代码-模是昂贵的!关于无模数的整洁之处在于它很容易并行化:

So you can definitely even beat C-style code with higher level objects - modulo is that expensive I guess! The neat thing about the no modulo one is it parallelizes quite easily:

addprocs(3)
@everywhere worker(j,N) = IntSet(j:j:N)
v4(N,M) = sum(union(pmap(j->worker(j,N),M)...))
@show v4(1000, [3,5])
@time v3(1000000000,[3,4,5]);  # bigger N than before
@time v4(1000000000,[3,4,5]);

给出

elapsed time: 12.279323079 seconds (2147831540 bytes allocated, 0.94% gc time)
elapsed time: 10.322364457 seconds (1019935752 bytes allocated, 0.71% gc time)

这不是好多了,但是我想是这样的.

which isn't much better, but its something I suppose.

这篇关于为IF编写可变数量的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆