2012-01-04 2 views
3

나는 (a, b) == (b, a) 그리고 that ((a, b), (c, d)) ==와 함께리스트에서 모든 가능한 쌍 쌍을 생성하고 싶다. ((c, d), (a, b))를 모든 a, b, c, d에 대해 계산합니다. 또한 필자가 제공하는 목록의 모든 요소는 별개라고 가정 할 수 있습니다. 프로파일 링은 실행 시간에 가까운 90 %가 지출 된 것을 알 (이것은 관용적 인의 미덕을 가지고이 목록 이해력을 어떻게 최적화 할 수 있습니까?

pairsOfPairs :: [a] -> [((a,a),(a,a))] 
pairsOfPairs xs = [((w,x),(y,z)) | w <- xs, x <- xs, y <- xs, z <- xs, 
         w < x, y < z, w < y, w /= z, x /= y, x /= z] 

하지만 매우 느립니다 :

내가했던 가장 먼저하는 일이 목록의 이해를 기록했다 이 함수와 다른 함수에서).

느린 이유는 n 개 요소의 목록에 대해 n^4 개의 후보 쌍 쌍을 생성하지만 제한으로 인해 결국 n!/(8 * (n-4)!) 우리가 적어도 8 번 너무 많은 일을하고 있다는 것을

속도를 높이기 위해 pairsOfPairs 함수를 다시 작성하는 방법이 있습니까? 분명히 그것은 여전히 ​​O (n^4)가 될 것이지만 나는 상수를 없애기를 희망하고 있습니다.


편집 :는 사실, 나는 거의 항상 의미, 길이 5의 목록이 함수를 호출이 결과에 팔분의 오는 = 15 개 요소가 있지만 기능은 5의 목록을 생성하는!^4 = 625 요소를 중간 단계로 사용합니다. 이러한 모든 중간 요소를 제거 할 수 있다면 약 40 배의 속도 향상을 얻을 수 있습니다!

+0

귀하의 첫 번째 단락과 같은 선택 쌍에 의해 거의 모든 불필요한 작업을 방지 할 수 있습니다하면 해당 A = B 형 =의 C = D 암시하는 것 같다 . 나는 그것이 당신이 의미하는 것이라고 생각하지 않습니다. – dave4420

+0

@ dave4420 '=='은 등가를 의미합니다. 즉, 쌍 (a, b)은 쌍 (b, a)과 동일하게 계산되어야하지만 a와 b는 같아야합니다. –

답변

8

작업량을 줄이는 간단한 방법은 가능한 한 빨리 필터링하는 것입니다. 즉시 사용할 수 있습니다로 조건을 확인하여

pairsOfPairs :: Ord a => [a] -> [((a,a),(a,a))] 
pairsOfPairs xs = [((w,x),(y,z)) | w <- xs, x <- xs, w < x, y <- xs, w < y, x /= y, 
            z <- xs, y < z, w /= z, x /= z] 

, 우리는 너무 나쁘지 않아 등 x <= w 각 쌍 (w,x) 작동 (N^2) O를 피하십시오. 이 분류되어있는 경우

그러나 더 많은 목록을 전처리에 의해 얻을 수있다, 우리는

ordPairs :: [a] -> [(a,a)] 
ordPairs (x:xs) = [(x,y) | y <- xs] ++ ordPairs xs 
ordPairs [] = [] 
+0

목록 이해에서 바인딩과 필터를 간단하게 다시 정렬하면 속도가 크게 달라졌습니다. 호기심에서 GHC가이 문제를 최적화 할 수없는 이유는 무엇입니까? 그것은 목록 내포가 do 표기법에 대한 설탕이고 블록은 필수적이기 때문입니까? –

+4

[이 답변] (http://stackoverflow.com/questions/6472883/using-list-elements-and-indices-together/6473153#6473153)의 구현을 좋아할 수도 있습니다.'pairs xs = [(x, y) | x : ys <- 꼬리 xs, y <- ys>'. –

+0

아주 좋아요, 대니얼, 저도 좋아해요. –

관련 문제