2016-03-31 16 views
5

Próbuję zrobić w Julii to, co robi ten kod Pythona. (Znajdź wszystkie pary z dwóch list, których łączna wartość wynosi powyżej 7.)Zrozumienia listy i krotki w Julii

#Python  
def sum_is_large(a, b): 
    return a + b > 7 

l1 = [1,2,3] 
l2 = [4,5,6] 
l3 = [(a,b) for a in l1 for b in l2 if sum_is_large(a, b)] 
print(l3) 

nie ma „jeśli” dla listowych w Julii. A jeśli używam filter(), nie jestem pewien, czy mogę przekazać dwa argumenty. Więc moja najlepsza propozycja jest taka:

#Julia 
function sum_is_large(pair) 
    a, b = pair 
    return a + b > 7 
end 

l1 = [1,2,3] 
l2 = [4,5,6] 

l3 = filter(sum_is_large, [(i,j) for i in l1, j in l2]) 
print(l3) 

nie znajdę to bardzo atrakcyjne. Moje pytanie brzmi: czy istnieje lepszy sposób w Julii?

Odpowiedz

6

Korzystanie pakiet bardzo popularny Iterators.jl, w Julia:

using Iterators  # install using Pkg.add("Iterators") 
filter(x->sum(x)>7,product(l1,l2)) 

to iterator wytwarzający pary. Aby uzyskać ten sam wydruk co OP:

Podejście iteracyjne ma potencjalnie znacznie większą pamięć. Oczywiście, można po prostu l3 = collect(l3iter) uzyskać wektor par.

@ user2317519, po prostu ciekawy, czy istnieje odpowiednik formularz iteratora dla Pythona?

+1

Podoba mi się iteratory. Możesz zrobić podobną rzecz w pythonie, jeśli importujesz itertools. Obawiam się jednak, że popełniłem błąd, próbując sprowadzić moje pytanie do prostego przykładu. Moim głównym problemem jest argumentacja krotki. Czy możemy udawać, że funkcja sum_is_large() jest naprawdę dość skomplikowana i że musi wielokrotnie używać zmiennych a i b. Czy istnieje sposób na przekazanie tych dwóch zmiennych bez robienia czegoś takiego jak a, b = para? –

+0

'a' i' b' są adresowalne jako 'x [1]' i 'x [2]' w 'bigfunc'. Możesz także zrobić 'x-> bigfunc (x ...)', a następnie zdefiniować 'bigfunc (a, b)'. Ten okrężny kod nie powinien kosztować zbyt wiele w wydajności, jeśli w ogóle. –

+1

@DanGetz w Pythonie znajduje się [itertools] (https://docs.python.org/2/library/itertools.html), który zasadniczo zawiera podobne iteratory, które julia "Iterators.jl". –

1

Może coś takiego:

julia> filter(pair -> pair[1] + pair[2] > 7, [(i, j) for i in l1, j in l2]) 
3-element Array{Tuple{Any,Any},1}: 
(3,5) 
(2,6) 
(3,6) 

chociaż zgodziłbym się, że nie wygląda to powinien być najlepszym sposobem ...

2

Inna opcja podobna do jednej z @DanGetz używając również Iterators.jl:

function expensive_fun(a, b) 
    return (a + b) 
end 

Następnie, jeśli warunek jest również skomplikowana, to można zdefiniować jako funkcję:

condition(x) = x > 7 

i ostatni , filtruj wyniki:

>>> using Iterators 
>>> result = filter(condition, imap(expensive_fun, l1, l2)) 

result to numer iteracyjny to jest obliczane tylko wtedy, gdy jest potrzebne (niedrogie) i może być zebrane w razie potrzeby collect(result).

Jedna linia, jeśli warunek filtra jest dość proste byłoby:

>>> result = filter(x->(x > 7), imap(expensive_fun, l1, l2)) 

Uwaga: imap działa natywnie dla dowolnej liczby parametrów.

0

Jestem zaskoczony nikt nie wspomina operator potrójny wdrożenie warunkowego:

julia> l3 = [sum_is_large((i,j)) ? (i,j) : nothing for i in l1, j in l2] 
3x3 Array{Tuple,2}: 
nothing nothing nothing 
nothing nothing (2,6) 
nothing (3,5) (3,6) 

lub nawet po prostu normalnym if blok w instrukcji złożonej, czyli

[ (if sum_is_large((x,y)); (x,y); end) for x in l1, y in l2 ] 

co daje ten sam wynik .

czuję ten wynik sprawia, że ​​o wiele więcej sensu niż filter(), ponieważ w Julii a in A, b in B konstrukt jest interpretowany wymiarowo, a więc wyjście jest w rzeczywistości „zrozumienie array” z odpowiednim wymiarowości, które wyraźnie w wielu przypadki byłyby korzystne i prawdopodobnie pożądane zachowanie (niezależnie od tego, czy uwzględnimy warunek, czy nie).

Podczas gdy filtr zawsze zwróci wektor. Oczywiście, jeśli chcesz uzyskać naprawdę, zawsze możesz uzyskać wynik: collect; lub dla takiego rozumienia listy warunkowej, jak tutaj, możesz po prostu usunąć z tablicy elementy nothing, wykonując l3 = l3[l3 .!= nothing].

Prawdopodobnie jest to jeszcze bardziej przejrzyste i nie mniej skuteczne niż podejście filter().

0

Można użyć @vcomp (wektor zrozumieniem) Makro w VectorizedRoutines.jl zrobić Pythona jak listowych:

using VectorizedRoutines 
[email protected] Int[i^2 for i in 1:10] when i % 2 == 0 # Int[4, 16, 36, 64, 100] 
3

Guards (if) są teraz dostępne w Julia v0.5 (obecnie w release- etap kandydat):

julia> v1 = [1, 2, 3]; 

julia> v2 = [4, 5, 6]; 

julia> v3 = [(a, b) for a in v1, b in v2 if a+b > 7] 
3-element Array{Tuple{Int64,Int64},1}: 
(3,5) 
(2,6) 
(3,6) 

Należy zauważyć, że generatory teraz dostępne są również:

julia> g = ((a, b) for a in v1, b in v2 if a+b > 7) 
Base.Generator{Filter{##18#20,Base.Prod2{Array{Int64,1},Array{Int64,1}}},##17#19}(#17,Filter{##18#20,Base.Prod2{Array{Int64,1},Array{Int64,1}}}(#18,Base.Prod2{Array{Int64,1},Array{Int64,1}}([1,2,3],[4,5,6])))