Check the sum of a certain array index

Hello everyone,

I would like to check the sum of certain indexes in the array. For example, I have the array:

a = [0, 0, 0, 1, 0, 1, 0, 1]
b = [1, 2, 3, 5]

I will check the sum of a[1], a[2], a[3], and a[5]. If the sum is = 0 then a is correct. I am looking forward to any help and replies.

The easiest way is probably

sum(a[b])

if you want to avoid the extra copy, you could do

sum(@view a[b])
2 Likes

Less easy, but benchmarked faster than @view method:

sum(Base.Fix1(getindex,a),b)
2 Likes

Thank you very much for the replies, @SteffenPL and @Dan . I have tried both of your solutions, and they worked very well. Once again, thank you very much.

P.S.:
I wanted to mark both of the replies as solutions, but I can’t. I am really sorry of it @SteffenPL

2 Likes

@divon Don’t worry, you should mark the most useful answer as the solution (and it’s not a competition :slight_smile: )

@Dan Given that @divon is maybe new to Julia, I would maybe recommend

x = zero(eltype(a))  # or x = 0 (for integers) or x = 1.0 (floats)
for i in b
    x += a[i]
end

which is (usually) equally fast and much easier to read (IMO) than the Base.Fix1 solution.

5 Likes

but the “good” vector a could also be like this [-1,2,-1,99,0,3,3,3]?

Thank you very much for your understanding, @SteffenPL. As you said, I am new to Julia. And it is easy to understand your recommendation.

I don’t know about the “good” vector, @rocco_sprmnt21. I wanted to check if the sum of some positions in the array was equal to 0.

I used the term “good” because I didn’t remember the one you used: “correct”.
The meaning of my question is if, given that the example of a=[…] that you proposed has only ‘0’ and ‘1’, the sum must be ‘0’ or all the values must be ‘0’ which is a tighter condition and easier to test, possibly.

Okay, I get what you mean, @rocco_sprmnt21. Actually, in my simulation, I will have:

a = [1, 0, 0, 1, 0, 1, 0, 1]
b = [1, 2, 3, 5]
z = [0 0 0 0 0 0 0 0; 0 0 0 0 0 0 0 1; 0 0 0 0 0 0 1 0; 0 0 0 0 0 0 1 1; ...; 1 1 1 1 1 1 1 1]

I will do an XOR between a and z, then check that the sum of the results of the XOR is equal to 0. If it is, then I will store which z is the culprit (I hope that you understand).

I would try

sum(a[i] for i in b) 

(That’s a response to the original question, not the latest. I don’t understand the latest question, unfortunately.)

2 Likes

Thank you very much for your reply, @DNF. I have tried it in my simulation, and it returns the same result as other solutions. Also, your solution gives me a new perspective on the for loop.

No, I’m sorry, but I don’t understand what you’re doing and how you transform the data.
If you give a complete example, maybe it’s easier for me to understand

In any case if a contains only 1 and 0 (or even boolean or even only positive numbers :grin: ) you could also use a different solution than sum

julia> @btime sum(a[i] for i in b)
  171.777 ns (1 allocation: 16 bytes)
1

julia> @btime all(i->a[i]==0,b)
  120.948 ns (0 allocations: 0 bytes)
false



julia> @btime findfirst(i->a[i]!=0,b) != nothing
  119.912 ns (0 allocations: 0 bytes)
true

EDIT: ignore the code below, I forgot that you had to index one array with the values of the other. The best notation is the anonymous function one because you want to a method that takes a function and avoids creating an intermediary array.

This can be more succinctly written as all(iszero, b).

This can be written as !isnothing(findfirst(!iszero, b)) or !isnothing(findfirst(>(0), b)) (if only positive numbers are allowed).

You can also replace any iszero by ==(0) or !iszero by !=(0) but I find those much less legible.

b contains the indexes not the values to check.
In any case it is useful to know the existence of these functions.

1 Like

I am sorry for not being detailed, I will try to explain it to you @rocco_sprmnt21.
In this task, the array is:

a = [1, 0, 0, 1, 0, 1, 0, 1]

Then I need to XOR array a with each of the arrays below:

z = [0 0 0 0 0 0 0 0; 0 0 0 0 0 0 0 1; 0 0 0 0 0 0 1 0; 0 0 0 0 0 0 1 1; 
     0 0 0 0 0 1 0 0; 0 0 0 0 0 1 0 1; 0 0 0 0 0 1 1 0; 0 0 0 0 0 1 1 1; 
     0 0 0 0 1 0 0 0; 0 0 0 0 1 0 0 1; 0 0 0 0 1 0 1 0; 0 0 0 0 1 0 1 1; 
     0 0 0 0 1 1 0 0; 0 0 0 0 1 1 0 1; 0 0 0 0 1 1 1 0; 0 0 0 0 1 1 1 1; 
     0 0 0 1 0 0 0 0; 0 0 0 1 0 0 0 1; 0 0 0 1 0 0 1 0; 0 0 0 1 0 0 1 1; 
     0 0 0 1 0 1 0 0; 0 0 0 1 0 1 0 1; 0 0 0 1 0 1 1 0; 0 0 0 1 0 1 1 1; 
     0 0 0 1 1 0 0 0; 0 0 0 1 1 0 0 1; 0 0 0 1 1 0 1 0; 0 0 0 1 1 0 1 1; 
     0 0 0 1 1 1 0 0; 0 0 0 1 1 1 0 1; 0 0 0 1 1 1 1 0; 0 0 0 1 1 1 1 1; 
     0 0 1 0 0 0 0 0; 0 0 1 0 0 0 0 1; 0 0 1 0 0 0 1 0; 0 0 1 0 0 0 1 1; 
     0 0 1 0 0 1 0 0; 0 0 1 0 0 1 0 1; 0 0 1 0 0 1 1 0; 0 0 1 0 0 1 1 1; 
     0 0 1 0 1 0 0 0; 0 0 1 0 1 0 0 1; 0 0 1 0 1 0 1 0; 0 0 1 0 1 0 1 1; 
     0 0 1 0 1 1 0 0; 0 0 1 0 1 1 0 1; 0 0 1 0 1 1 1 0; 0 0 1 0 1 1 1 1; 
     0 0 1 1 0 0 0 0; 0 0 1 1 0 0 0 1; 0 0 1 1 0 0 1 0; 0 0 1 1 0 0 1 1; 
     0 0 1 1 0 1 0 0; 0 0 1 1 0 1 0 1; 0 0 1 1 0 1 1 0; 0 0 1 1 0 1 1 1; 
     0 0 1 1 1 0 0 0; 0 0 1 1 1 0 0 1; 0 0 1 1 1 0 1 0; 0 0 1 1 1 0 1 1; 
     0 0 1 1 1 1 0 0; 0 0 1 1 1 1 0 1; 0 0 1 1 1 1 1 0; 0 0 1 1 1 1 1 1; 
     0 1 0 0 0 0 0 0; 0 1 0 0 0 0 0 1; 0 1 0 0 0 0 1 0; 0 1 0 0 0 0 1 1; 
     0 1 0 0 0 1 0 0; 0 1 0 0 0 1 0 1; 0 1 0 0 0 1 1 0; 0 1 0 0 0 1 1 1; 
     0 1 0 0 1 0 0 0; 0 1 0 0 1 0 0 1; 0 1 0 0 1 0 1 0; 0 1 0 0 1 0 1 1; 
     0 1 0 0 1 1 0 0; 0 1 0 0 1 1 0 1; 0 1 0 0 1 1 1 0; 0 1 0 0 1 1 1 1; 
     0 1 0 1 0 0 0 0; 0 1 0 1 0 0 0 1; 0 1 0 1 0 0 1 0; 0 1 0 1 0 0 1 1; 
     0 1 0 1 0 1 0 0; 0 1 0 1 0 1 0 1; 0 1 0 1 0 1 1 0; 0 1 0 1 0 1 1 1; 
     0 1 0 1 1 0 0 0; 0 1 0 1 1 0 0 1; 0 1 0 1 1 0 1 0; 0 1 0 1 1 0 1 1; 
     0 1 0 1 1 1 0 0; 0 1 0 1 1 1 0 1; 0 1 0 1 1 1 1 0; 0 1 0 1 1 1 1 1; 
     0 1 1 0 0 0 0 0; 0 1 1 0 0 0 0 1; 0 1 1 0 0 0 1 0; 0 1 1 0 0 0 1 1; 
     0 1 1 0 0 1 0 0; 0 1 1 0 0 1 0 1; 0 1 1 0 0 1 1 0; 0 1 1 0 0 1 1 1; 
     0 1 1 0 1 0 0 0; 0 1 1 0 1 0 0 1; 0 1 1 0 1 0 1 0; 0 1 1 0 1 0 1 1; 
     0 1 1 0 1 1 0 0; 0 1 1 0 1 1 0 1; 0 1 1 0 1 1 1 0; 0 1 1 0 1 1 1 1; 
     0 1 1 1 0 0 0 0; 0 1 1 1 0 0 0 1; 0 1 1 1 0 0 1 0; 0 1 1 1 0 0 1 1; 
     0 1 1 1 0 1 0 0; 0 1 1 1 0 1 0 1; 0 1 1 1 0 1 1 0; 0 1 1 1 0 1 1 1; 
     0 1 1 1 1 0 0 0; 0 1 1 1 1 0 0 1; 0 1 1 1 1 0 1 0; 0 1 1 1 1 0 1 1; 
     0 1 1 1 1 1 0 0; 0 1 1 1 1 1 0 1; 0 1 1 1 1 1 1 0; 0 1 1 1 1 1 1 1; 
     1 0 0 0 0 0 0 0; 1 0 0 0 0 0 0 1; 1 0 0 0 0 0 1 0; 1 0 0 0 0 0 1 1; 
     1 0 0 0 0 1 0 0; 1 0 0 0 0 1 0 1; 1 0 0 0 0 1 1 0; 1 0 0 0 0 1 1 1; 
     1 0 0 0 1 0 0 0; 1 0 0 0 1 0 0 1; 1 0 0 0 1 0 1 0; 1 0 0 0 1 0 1 1; 
     1 0 0 0 1 1 0 0; 1 0 0 0 1 1 0 1; 1 0 0 0 1 1 1 0; 1 0 0 0 1 1 1 1; 
     1 0 0 1 0 0 0 0; 1 0 0 1 0 0 0 1; 1 0 0 1 0 0 1 0; 1 0 0 1 0 0 1 1; 
     1 0 0 1 0 1 0 0; 1 0 0 1 0 1 0 1; 1 0 0 1 0 1 1 0; 1 0 0 1 0 1 1 1; 
     1 0 0 1 1 0 0 0; 1 0 0 1 1 0 0 1; 1 0 0 1 1 0 1 0; 1 0 0 1 1 0 1 1; 
     1 0 0 1 1 1 0 0; 1 0 0 1 1 1 0 1; 1 0 0 1 1 1 1 0; 1 0 0 1 1 1 1 1; 
     1 0 1 0 0 0 0 0; 1 0 1 0 0 0 0 1; 1 0 1 0 0 0 1 0; 1 0 1 0 0 0 1 1; 
     1 0 1 0 0 1 0 0; 1 0 1 0 0 1 0 1; 1 0 1 0 0 1 1 0; 1 0 1 0 0 1 1 1; 
     1 0 1 0 1 0 0 0; 1 0 1 0 1 0 0 1; 1 0 1 0 1 0 1 0; 1 0 1 0 1 0 1 1; 
     1 0 1 0 1 1 0 0; 1 0 1 0 1 1 0 1; 1 0 1 0 1 1 1 0; 1 0 1 0 1 1 1 1; 
     1 0 1 1 0 0 0 0; 1 0 1 1 0 0 0 1; 1 0 1 1 0 0 1 0; 1 0 1 1 0 0 1 1; 
     1 0 1 1 0 1 0 0; 1 0 1 1 0 1 0 1; 1 0 1 1 0 1 1 0; 1 0 1 1 0 1 1 1; 
     1 0 1 1 1 0 0 0; 1 0 1 1 1 0 0 1; 1 0 1 1 1 0 1 0; 1 0 1 1 1 0 1 1; 
     1 0 1 1 1 1 0 0; 1 0 1 1 1 1 0 1; 1 0 1 1 1 1 1 0; 1 0 1 1 1 1 1 1; 
     1 1 0 0 0 0 0 0; 1 1 0 0 0 0 0 1; 1 1 0 0 0 0 1 0; 1 1 0 0 0 0 1 1; 
     1 1 0 0 0 1 0 0; 1 1 0 0 0 1 0 1; 1 1 0 0 0 1 1 0; 1 1 0 0 0 1 1 1; 
     1 1 0 0 1 0 0 0; 1 1 0 0 1 0 0 1; 1 1 0 0 1 0 1 0; 1 1 0 0 1 0 1 1; 
     1 1 0 0 1 1 0 0; 1 1 0 0 1 1 0 1; 1 1 0 0 1 1 1 0; 1 1 0 0 1 1 1 1; 
     1 1 0 1 0 0 0 0; 1 1 0 1 0 0 0 1; 1 1 0 1 0 0 1 0; 1 1 0 1 0 0 1 1; 
     1 1 0 1 0 1 0 0; 1 1 0 1 0 1 0 1; 1 1 0 1 0 1 1 0; 1 1 0 1 0 1 1 1; 
     1 1 0 1 1 0 0 0; 1 1 0 1 1 0 0 1; 1 1 0 1 1 0 1 0; 1 1 0 1 1 0 1 1; 
     1 1 0 1 1 1 0 0; 1 1 0 1 1 1 0 1; 1 1 0 1 1 1 1 0; 1 1 0 1 1 1 1 1; 
     1 1 1 0 0 0 0 0; 1 1 1 0 0 0 0 1; 1 1 1 0 0 0 1 0; 1 1 1 0 0 0 1 1; 
     1 1 1 0 0 1 0 0; 1 1 1 0 0 1 0 1; 1 1 1 0 0 1 1 0; 1 1 1 0 0 1 1 1; 
     1 1 1 0 1 0 0 0; 1 1 1 0 1 0 0 1; 1 1 1 0 1 0 1 0; 1 1 1 0 1 0 1 1; 
     1 1 1 0 1 1 0 0; 1 1 1 0 1 1 0 1; 1 1 1 0 1 1 1 0; 1 1 1 0 1 1 1 1; 
     1 1 1 1 0 0 0 0; 1 1 1 1 0 0 0 1; 1 1 1 1 0 0 1 0; 1 1 1 1 0 0 1 1; 
     1 1 1 1 0 1 0 0; 1 1 1 1 0 1 0 1; 1 1 1 1 0 1 1 0; 1 1 1 1 0 1 1 1; 
     1 1 1 1 1 0 0 0; 1 1 1 1 1 0 0 1; 1 1 1 1 1 0 1 0; 1 1 1 1 1 0 1 1; 
     1 1 1 1 1 1 0 0; 1 1 1 1 1 1 0 1; 1 1 1 1 1 1 1 0; 1 1 1 1 1 1 1 1; 

The XOR operation is using:

c = zeros(8)
for i in 1 : 2^8
    for j in 1 : 8
        c[j] = xor(a[j], z[i, j]
    end
end

Using one of the solutions above, I will check the sum of array c

res = []
b = [1, 2, 3, 5]
sum_c = sum(Base.Fix1(getindex,a), b)
if sum_c == 0
    res = c
end

And use the array that has sum = 0 as the result.

z = [1, 0, 0, 0, 0, 0, 0, 0]
c = [0, 0, 0, 1, 0, 1, 0, 1]

The operation is actually done in the while loop, and when sum_c = 0, the loop will stop and give the result.
(I hope you understand now because it is really hard to create array z) :sweat_smile:

If this is the actual code, it could be greatly simplified using the following function. You don’t really need to create and store the array z before hand. Create the binary representation vector of each byte one by one until your criterion is satisfied. This will be simple and fast because you will return as early as possible.

function test_xor_sum(a, b)
    for i in 0:255
        z = digits(i, base=2, pad=8)
        all(a[j] == z[j] for j in b) && return z
    end
end

a = [1, 0, 0, 1, 0, 1, 0, 1]
b = [1, 2, 3, 5]
@btime test_xor_sum($a, $b) # 363.462 ns (2 allocations: 256 bytes)
1 Like

Thank you very much for the solution, @Seif_Shebl. I have tried it and it worked well because, in my previous method (where I needed to generate array z), Julia returned “Out of Memory Error” when I tried to generate an array with length 2^32. :sweat_smile:

This could even be made faster if you like Iterators. Immutable containers like Tuples allocate zero memory, that’s why it’s faster.

function test_xor_sum(a, b)
    for z in Iterators.product(ntuple(_->0:1,8)...)
        all(a[j] == z[j] for j in b) && return z
    end
end

a = (1, 0, 0, 1, 0, 1, 0, 1)
b = (1, 2, 3, 5)
@btime test_xor_sum($a, $b) # 140.418 ns (0 allocations: 0 bytes)

Another way, is to forego all the iterations and consider what the solution should be:

julia> a = (1, 0, 0, 1, 0, 1, 0, 1)
(1, 0, 0, 1, 0, 1, 0, 1)

julia> b = (1, 2, 3, 5)
(1, 2, 3, 5)

julia> function test_xor_sum2(a, b)
           ntuple(i -> i ∈ b ? a[i] : 0, length(a))
       end
test_xor_sum2 (generic function with 1 method)

julia> test_xor_sum2(a,b)
(1, 0, 0, 0, 0, 0, 0, 0)

julia> @btime test_xor_sum2($a,$b);
  19.748 ns (0 allocations: 0 bytes)

This is at least a solution, there can be an issue of which solution is returned for which iteration order.

I still don’t understand the context.
However, I add an observation.
Since we have octets of ‘0’ and ‘1’, the xor operation can be done directly on the decimal numbers corresponding to these octets, rather than vectors (or tuples).
So there would be no need to construct the z array, for example…

From what I understand so far, it seems more like a problem to be solved by hand.
A solution could be the following
The xor of a with z reproduces all z in random order (that is, the bit octets of the numbers from ‘0’ to ‘255’).
Associating b to the number 232 = 2^7+2^6+2^5+2^3 a number which certainly has the bits at ‘0’ in the positions (1,2,3,5) from left to rigth is 255-232=23.
That is 00010111

1 Like