Skip every nth element of array

Viewed 592

How can I remove every nth element from an array in julia? Let's say I have the following array: a = [1 2 3 4 5 6] and I want b = [1 2 4 5]

In javascript I would do something like:

b = a.filter(e => e % 3);

How can it be done in Julia?

5 Answers

Your question title and text ask different questions. The title asks how to skip the Nth element, whereas the Javascript code snippet details how to skip elements based on their value, not their index.

Skipping by Value

We can do this using filter.

filter((x) -> x % 3 != 0, a)

This is basically equivalent to your Javascript code. We can, incidentally, also use broadcasting.

a[a .% 3 .!= 0]

This is more akin to code you would see in array-oriented languages like MATLAB and R.

Skipping by Index

With an extra enumerate call, we can get the indices to operate on.

map((x) -> x[2], Iterators.filter(((x) -> x[1] % 3 != 0), enumerate(a)))

This is roughly what you'd do in Python. enumerate to get the indices, filter to purge, then map to eliminate the now-unnecessary indices.

Or we can, again, use broadcasting.

a[(1:length(a)) .% 3 .!= 0]

If you need skipping by index the most elegant way is to use InvertedIndices

julia> using InvertedIndices  # or using DataFrames


julia> a[Not(3:3:end)]
4-element Vector{Int64}:
 1
 2
 4
 5

As you can see all your job here is to provide a range of indices you wish to skip.

If you want to filter by the index, one convenient way is using a comprehension:

julia> a = 10:10:100;

julia> [a[i] for i in eachindex(a) if i % 3 != 0] |> permutedims
1×7 Matrix{Int64}:
 10  20  40  50  70  80  100

julia> vec(ans) == [a[1 + 3(j-1)÷2] for j in 1:7]
true

This implicitly involves Iterators.filter, and collects the generator. You can also use this to filter by value, although the eager filter is probably more efficient:

julia> a = 1:10;

julia> [x for x in a if x%3!=0] |> permutedims
1×7 Matrix{Int64}:
 1  2  4  5  7  8  10

Perhaps it's interesting to time all of these:

julia> using BenchmarkTools, InvertedIndices

julia> a = rand(1000);  # filter by index

julia> i1 = @btime [$a[1 + 3(j-1)÷2] for j in 1:667];
  373.162 ns (1 allocation: 5.38 KiB)

julia> i2 = @btime $a[eachindex($a) .% 3 .!= 0];
  1.387 μs (4 allocations: 9.80 KiB)

julia> i3 = @btime [$a[i] for i in eachindex($a) if i % 3 != 0];
  3.557 μs (11 allocations: 16.47 KiB)

julia> i4 = @btime map((x) -> x[2], Iterators.filter(((x) -> x[1] % 3 != 0), enumerate($a)));
  4.202 μs (11 allocations: 16.47 KiB)

julia> i5 = @btime $a[Not(3:3:end)];
  84.333 μs (4655 allocations: 182.28 KiB)

julia> i1 == i2 == i3 == i4 == i5
true

julia> a = rand(1:99, 1000);  # filter by value

julia> v1 = @btime filter(x -> x%3!=0, $a);
  532.185 ns (1 allocation: 7.94 KiB)

julia> v2 = @btime [x for x in $a if x%3!=0];
  5.465 μs (11 allocations: 16.47 KiB)

julia> v1 == v2
true

This should help you:

b = a[Bool[i %3 != 0 for i = 1:length(a)]]
a[a .% 2 .!= 0]

please find the link with code.

Related