Julia 为IF编写数量可变的参数

Julia 为IF编写数量可变的参数,julia,Julia,我正在尝试编写一个函数来解决此问题的任何通用版本: 如果我们列出10以下的所有自然数,它们是3或5的倍数,我们得到3、5、6和9。这些倍数之和是23 求1000以下所有3或5的倍数之和 我解决这个问题的方法是: multiples = Array(Int, 0) [ (i % 3 == 0 || i % 5 == 0) && push!(multiples, i) for i in 1:1000 ] sum(multiples) 我想写一个函数,在本例中取一个倍数数组,[3,5

我正在尝试编写一个函数来解决此问题的任何通用版本:

如果我们列出10以下的所有自然数,它们是3或5的倍数,我们得到3、5、6和9。这些倍数之和是23

求1000以下所有3或5的倍数之和

我解决这个问题的方法是:

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

我如何才能最有效地做到这一点?这会涉及元编程吗?代码不必是列表格式


谢谢

我想到的第一件事是以下内容,使用模除法和函数式:

v1(N,M) = sum(filter(k->any(j->k%j==0,M), 1:N))
但我想调查一些替代方案,因为这有两个问题:

两个级别的匿名函数,Julia还没有很好地优化。 从该范围创建一个临时数组,然后求和。 因此,这里是最明显的替代方案,一行程序的C风格版本:

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
但后来我又想了想,记得在什么地方读到过,模除是一种缓慢的运算。我想看看整数集是如何执行的——一个专门用于整数的集合。因此,这里是另一个单行程序,不使用任何模块划分的IntSets,以及一种功能样式

v3(N,M) = sum(union(map(j->IntSet(j:j:N), M)...))
将映射扩展为for循环并重复应用union!对于一个整数集来说并没有太大的改进,所以我不会在这里包括它。要分解这一点:

IntSetj:j:N是j和N之间j的所有倍数 j->IntSetj:j:N是返回该IntSet的匿名函数 mapj->IntSetj:j:N,M将该函数应用于M中的每个j,并返回一个向量{IntSet}。 这个将向量展开为并集的参数 union创建一个整数集,该整数集是其参数的并集——在本例中,是M中数字的所有倍数 然后我们把它加起来完成 我用

N,M = 10000000, [3,4,5]
这给了你

一行程序:分配了2.857292874秒826006352字节,gc时间的10.49% C样式:0.190581908秒分配176字节 IntSet无模:分配0.121820101秒16781040字节 所以你甚至可以用更高级的对象来击败C风格的代码——我想模是很昂贵的!关于无模一的巧妙之处在于它很容易并行化:

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)

这并不是更好,但我想是这样的。

好的,这是我最新的答案

根据@iaindanning答案中的基准,击败的方法是他的v2。我下面的方法似乎要快得多,但我不够聪明,无法将其推广到长度大于2的输入向量。一个好的数学家应该能够改进我的答案

快速直觉:对于lengthM=2的情况,问题归结为M[1]到N的所有倍数之和加上M[2]到N的所有倍数之和,其中,为了避免重复计算,我们需要减去M[1]*M[2]到N的所有倍数之和。对于M>2,可以实现类似的算法,但重复计算的问题很快变得复杂得多。我怀疑一个通用的算法肯定会存在,这是一个在组合数学领域里经常出现的问题,但我并不知道这一点

以下是我的方法f1与v2的测试代码:

时间安排如下:

elapsed time: 4.744e-6 seconds (96 bytes allocated)
elapsed time: 0.201480996 seconds (96 bytes allocated)

抱歉,这是一个有趣的问题,但恐怕我必须回去工作:-如果有机会,我会稍后再查看…

我可能误读了,但我认为OP的问题是数组可以由任意多个数字组成。谢谢!只是出于好奇,我是朱莉娅的新朋友,在文档中我可以找到关于任何人的信息吗?我不是说现在我已经看到你在使用它了,而是在之前?所以为了快速参考,请在REPL上键入?any。要发现它,您需要查看标准库的Iterables部分:,我承认这不是最容易找到的。我是从别人的代码中看到的!嗨,Iaindanning,你能理解为什么我在下面的答案中的方法运行得更快吗?速度太快了,我有点怀疑我做了什么蠢事,不知怎么的,我在作弊。如果相关的话,我在朱诺工作。干杯。嘿,科林,据我所知,这要快得多,而且正确!这是一个很好的方法,可以直接解决| M |=2的情况。它的速度很快,因为我怀疑它不进行任何模块划分,也没有令人尴尬的匿名函数。我不知道如何写它的一般版本,虽然…哎呀,并没有仔细阅读问题之前,潜水。现在更新答案。
elapsed time: 4.744e-6 seconds (96 bytes allocated)
elapsed time: 0.201480996 seconds (96 bytes allocated)