2013-04-02 3 views
3

У меня есть этот код, но он не делает то, что я хочу полностью, я беру список кортежей;Устранение дубликатов полностью в Haskell

[(3,2),(1,2),(1,3),(1,2),(4,3),(3,2),(1,2)] 

и дает

[(1,3),(4,3),(3,2),(1,2)] 

, но я хочу, чтобы дать

[(1,3),(4,3)] 

, где я делаю неправильно? Заранее спасибо.

eliminate :: [(Int,Int)] -> [(Int,Int)] 
eliminate [] = [] 
eliminate (x:xs) 
    | isTheSame xs x = eliminate xs 
    | otherwise  = x : eliminate xs 


isTheSame :: [(Int,Int)] -> (Int,Int) -> Bool 
isTheSame [] _ = False 
isTheSame (x:xs) a 
    | (fst x) == (fst a) && (snd x) == (snd a) = True 
    | otherwise     = isTheSame xs a 
+5

Что вы подразумеваете под «полностью», почему именно следует исключать '(3,2)' и '(1,2)'? – Landei

+0

Я ищу функцию, которая полностью исключает дубликаты, только там должны быть уникальные, я должен изменить свою реализацию:/ – Karavana

ответ

7

Код почти правильно. Просто измените эту строку

| isTheSame xs x = eliminate xs 

в

| isTheSame xs x = eliminate $ filter (/=x) xs 

Причина заключается в том, что если x содержится в xs, вы хотите удалить все вхождений x.

Тем не менее, есть несколько частей в образце коды, которые могут быть выражены более элегантно:

  • (fst x) == (fst a) && (snd x) == (snd a) такими же, как x == a
  • isTheSame таких же, как elem, только с его аргументами обратными

Таким образом, мы могли бы выразить функцию eliminate так:

eliminate [] = [] 
eliminate (x:xs) 
    | x `elem` xs = eliminate $ filter (/=x) xs 
    | otherwise = x : eliminate xs  
+0

ow да! Я отфильтровал эту часть, чтобы исключить x из части xs, но я не смог ее обойти. – Karavana

+2

@Karavana: Проверьте мое редактирование, вы должны использовать 'elem' вместо своей пользовательской, узкоспециализированной' isTheSame' функции (который также имеет странное имя) –

+0

Я как раз собирался предложить это изменение. –

5

Это следует сделать это:

-- all possibilities of picking one elt from a domain 
pick :: [a] -> [([a], a)] 
pick []  = [] 
pick (x:xs) = (xs,x) : [ (x:dom,y) | (dom,y) <- pick xs] 

unique xs = [x | (xs,x) <- pick xs, not (elem x xs)] 

Тестирование:

*Main Data.List> unique [(3,2),(1,2),(1,3),(1,2),(4,3),(3,2),(1,2)] 
[(1,3),(4,3)] 

here Больше и Splitting list into a list of possible tuples


После Landei's lead, вот короткая версия (хотя она будет возвращать свои результаты сортируются):

import Data.List 

unique xs = [x | [x] <- group . sort $ xs] 
+0

хорошая реализация Будет, я ценю ваши усилия, но меня интересует, что случилось с моей реализацией, но ваш прекрасный tho :) – Karavana

+1

@ Karavana проблем нет! :) –

3

Сокращенный вариант (но результаты будут отсортированы):

import Data.List 

eliminate :: [(Int,Int)] -> [(Int,Int)] 
eliminate = concat . filter ((== 1) . length) . group . sort 

Или с Maybe (спасибо, Маримутху):

import Data.List 
import Data.Maybe 

eliminate = mapMaybe f . group . sort where f [x] = Just x; f _ = Nothing 

Думая о ...мы могли бы использовать списки вместо Maybe:

import Data.List 

eliminate = (>>= f) . group . sort where f [x] = [x]; f _ = [] 
+0

Is есть причина для использования join вместо concat? При использовании concat импорт Control.Monad не требуется. – kaan

+0

Нет. Спасибо, я исправил его. – Landei

+1

'' 'elim = mapMaybe f. group. sort where f [x ] = Just x; f_ = Nothing''', так как '' 'catMaybes. Map f''' просто' '' mapMaybe f''' –

4

Неэффективная эталонная реализация.

import Data.List 

dups xs = xs \\ nub xs 
eliminate xs = filter (`notElem` dups xs) xs 
Смежные вопросы