How to impose condition on n-tuple?

Is it possible to place some condition over the ements of Vector of Tuples to creat another Vector of Tuples?

For example, I have buch of tuples demonstraing some properties of devices (property1, property2, deice_ID). besides there are two other vectors IDs, and a Super_property vector showing a special property of a device (alaways length(ID) = length( Super_P)) . For instance, device with ID 4 is special only if it has the proprty of 25. Based o these how to crreate a vector that only returns the special devices?


Devices = [(25, 504, 4), (24, 518, 9) , (20, 250, 7), (29, 248, 4), (29, 283, 4), (22, 528, 9) , (21, 270, 4), (27, 218, 7), (25, 123, 4), (32, 123, 9)]

ID  = [4,7,9]
Super_P = [25, 27, 22]

This is what I’m looking for:

Specials = [ [ (25, 504, 4), (25, 123, 4) ] , (27, 218, 7), (22, 528, 9)]

Something like this?

julia> Devices = [(25, 504, 4), (24, 518, 9) , (20, 250, 7), (29, 248, 4), (29, 283, 4), (22, 528, 9) , (21, 270, 4), (27, 218, 7), (28, 123, 4), (32, 123, 9)];
julia> ID  = [4,7,9];
julia> Super_P = [25, 27, 22];

julia> function is_special(device)
          prop1, prop2, id = device
          i = findfirst(==(id), ID)
          return prop1 == Super_P[i]
       end
is_special (generic function with 1 method)

julia> filter(is_special, Devices)
3-element Vector{Tuple{Int64, Int64, Int64}}:
 (25, 504, 4)
 (22, 528, 9)
 (27, 218, 7)

Here I used findfirst to look for the index of id in the ID array, and then compare prop1 to the special value stored at the same index in Super_P. (If it is not guaranteed that all possible ids are listed in ID, then you’d have to handle the special case where you don’t find the given id in ID.)

filter is then used to only keep the devices matching the criterion in Devices.

2 Likes

This sounds like it would be easier to maintain if you made a struct,

struct Device
    property_1::Int
    property_2::Int
    id::Int
end

is_special(d::Device, id, property) = d.id == id && d.property_1 == property

devices = [Device(d...) for d in Devices]

special = [filter(devices) do d
    is_special(d, i, p)
end for (i, p) in zip(ID, Super_P)]

3 Likes

@ffevotte, is there an easy way to group the tuples that result from your code?

A laborious way:

is_special(device) = device[1] == Super_P[findfirst(==(device[3]), ID)]

sd = filter(is_special, Devices)
ix = getindex.(sd,3)
specials = [sd[ix .== u] for u in unique(ix)]
1 Like

Ah, it looks like the grouping requirement arrived in an edit to the question, after I posted my answer… @Kevin_12 please don’t do that: it makes it rather hard to follow threads when posts are substantially modified without warning…

LGTM.

An other way, probably as laborious as yours :slight_smile:

is_special(device) = device[1] == Super_P[findfirst(==(device[3]), ID)]
specials = filter(is_special, Devices)
specials_grouped = [filter(d->d[3]==id, specials) for id in ID]

But I do agree with @gustaphe: it’s awkward to manipulate tuples here. Since we know that we are manipulating “devices”, it’s best to declare a specific type and use that.

2 Likes
fandl=[(first(D),last(D)) for D in Devices]
Devices[[findfirst(isequal(spid), fandl) for spid in zip(Super_P,ID)]]

1 Like

Not at all, your comprehension with a filter inside looks pretty good. Thanks.

1 Like

I just got back to my computer, and I’m frankly shocked that my phone written solution ran perfectly.

2 Likes

this should do just what is required

getindex.([Devices],[findall(isequal(spid), getindex.(Devices, [[1,3]])) for spid in zip(Super_P,ID)])


3-element Vector{Vector{Tuple{Int64, Int64, Int64}}}:
 [(25, 504, 4), (25, 123, 4)]
 [(27, 218, 7)]
 [(22, 528, 9)]
filter(t->(t[1],t[3]) in zip(Super_P,ID), Devices)

4-element Vector{Tuple{Int64, Int64, Int64}}:
 (25, 504, 4)
 (22, 528, 9)
 (27, 218, 7)
 (25, 123, 4)