【问题标题】:Julia: loop over rows of matrix (or not)Julia:遍历矩阵行(或不循环)
【发布时间】:2022-01-22 18:40:49
【问题描述】:

假设我有一个这样的字符串向量

julia> R = ["ABC","DEF"]
2-element Vector{String}:
"ABC"
"DEF"

现在我复制元素以形成一个 2*2 矩阵:

julia> x = [R R]
2×2 Matrix{String}:
"ABC"  "ABC"
"DEF"  "DEF"

我想要实现的是连接矩阵每一行的字符串。我能想到的最好的是

julia> [join(x[i,:]) for i in 1:length(x)÷2]
2-element Vector{String}:
"ABCABC"
"DEFDEF"

它给出了想要的结果。

是否有替代解决方案(没有显式循环)?我试图找到广播的有效语法但失败了。

(我尝试的另一个想法是

julia> x = [R,R]
2-element Vector{Vector{String}}:
["ABC", "DEF"]
["ABC", "DEF"]

julia> join.(x)
2-element Vector{String}:
"ABCDEF"
"ABCDEF"

这是“更简单”但显然没有给出预期的结果。)

【问题讨论】:

  • 如果你实际上是从R而不是从矩阵开始,你可以只做repeat.(R, 2)而不是形成矩阵
  • 是的,我从R开始。 --- 哦,repeat. 也是一个不错的方法。

标签: matrix iterator julia


【解决方案1】:

我总结了一些将函数应用于矩阵的的选项:

julia> x = ["ABC" "ABC"; "DEF" "DEF"]
2×2 Matrix{String}:
 "ABC"  "ABC"
 "DEF"  "DEF"

1。使用mapslices 的类似地图的语法

您要查找的函数可能是mapslices(f, A; dims):

julia> mapslices(join, x; dims=[2])
2×1 Matrix{String}:
 "ABCABC"
 "DEFDEF"

这是一个在数组的“切片”而不是元素上调用的“映射”,沿着dims 给出的维度。

2。广播语法使用eachrow

eachrow(A::AbstractVecOrMat) 在矩阵的行上创建一个迭代器,为每个行返回数组 view

julia> join.(eachrow(x))
2-element Vector{String}:
 "ABCABC"
 "DEFDEF"

3。结合普通的mapeachrow

julia> map(join, eachrow(x))
2-element Vector{String}:
 "ABCABC"
 "DEFDEF"

使用 BenchmarkTools 在 100x100 随机数组上,这三种方法的性能似乎相同:

method performance
1. @btime mapslices(join, x; dims=[2]) 1.379 ms (21935 allocations: 4.92 MiB)
2. @btime join.(eachrow(x)) 1.296 ms (21206 allocations: 4.82 MiB)
3. @btime map(join, eachrow(x)) 1.294 ms (21304 allocations: 4.82 MiB)

(对于更灵活的地图切片具有较小的开销)

【讨论】:

  • 谢谢,这是一个很好的解决方案。让我为这个问题添加另一种不太正确的方法。
  • 哦,是的,如果您可以控制矩阵的形成方式,您可以在那里处理问题:-)
  • 是的,但是您的答案是完美的,因为它解决了这个问题(如何遍历行)。
【解决方案2】:

看到你在cmets中说你是从R开始的,没有必要形成x来得到你想要的东西,直接重复R的元素:

julia> repeat.(R, 2) == join.(eachrow([R R]))
true

julia> @btime repeat.($R, 2);
  61.283 ns (3 allocations: 128 bytes)

julia> @btime join.(eachrow([$R $R]));
  354.392 ns (11 allocations: 704 bytes)

在这种情况下,它分配了大约四分之一,速度提高了 5 倍。

编辑添加了一个更接近另一个答案的基准 - 一个长度为 3 个随机字符串的 100 元素向量:

julia> using Random

julia> R = [randstring(3) for _ ∈ 1:100];

julia> @btime join.(eachrow([$R for _ ∈ 1:100]));
  1.607 ms (1103 allocations: 138.62 KiB)

julia> @btime repeat.($R, 100);
  43.497 μs (101 allocations: 33.69 KiB)

所以在这里,我们在时间上的差异更像是 40 倍(尽管现在对什么进行基准测试不太明显,因为除了对 x 的不同行的串联进行基准测试之外,还可以考虑不同的方法来构造 @987654327 @来自R,效率不同)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多