2013-10-09 7 views
2

Я имею дело с большим списком (порядка 10^5) идентификаторов (которые являются длинными типами данных). Я должен найти дубликаты в списке идентификаторов. Но я ограничусь использованием рубина.Самый быстрый способ найти дублирующее число в большом списке

Здесь я нашел способ сделать это. Я пройду список и поставлю идентификатор в хэш, но прежде чем вставлять его в хэш, я проверю, что он уже находится в хеше или нет.

Я не уверен в сложности хеша в RUBY.

Пожалуйста, предложите мне лучшую идею.

+2

Либо рубин, или что? – sawa

+1

Ваша идея звучит неплохо. Это на самом деле медленно? Пожалуйста, поделитесь своими результатами. – Stefan

+0

Что заставляет вас думать, что сложность хэшей в Ruby будет отличаться от других языков? Хеширование, как правило, считается временем O (1), если коэффициент нагрузки не слишком близко к 1. – pjs

ответ

4

Почему бы вам не использовать Set?

require 'set' 

set = Set.new 
numbers.each do |number| 
    puts "Number #{number} is already in the set" unless set.add?(number) 
end 

Или просто найти дубликаты:

require 'set' 
set = Set.new 
duplicates = numbers.reject { |number| set.add?(number) } 
+0

Хорошее решение. Обратите внимание, что это эквивалентно тому, что предлагает исходный плакат (используя «Hash»). Решение - это «O (n)». –

+0

Да, это почти то же самое, за исключением того, что он может использовать меньше памяти (зависит от реализации). –

+0

Теоретически да, но на практике существует ли какая-либо реализация, которая не использует 'Hash' для обработки' Set'? –

2

Давайте посмотрим, что Benchmark говорит:

require 'benchmark' 
require 'set' 


def rand_n(n, max) 
    randoms = Array.new 
    loop do 
    randoms << rand(max) 
    return randoms.to_a if randoms.size >= n 
    end 
end 

numbers = rand_n(10000, 10000000) 

counter = Hash.new 
time = Benchmark.measure do 
    for number in numbers 
    if counter.has_key?(number) 
     counter[number] = counter[number]+1 
    else 
     counter[number]=1 
    end 
    end 
duplicates = counter.select{|k,v| v > 1} 
end 
puts time 

time1 = Benchmark.measure do 
    counts = Hash.new{|h,k| h[k] = 0 } 
    numbers.each{|n| counts[n] +=1} 
    duplicates = counts.select{|k,v| v > 1} 
end 
puts time1 

set = Set.new 
time2 = Benchmark.measure do 
    duplicates = numbers.reject { |number| set.add?(number) } 
end 

puts time2 

И вывод:

0.000000 0.000000 0.000000 ( 0.006114) 
    0.010000 0.000000 0.010000 ( 0.008529) 
    0.010000 0.000000 0.010000 ( 0.006098) 

EDIT: Обновлено с дублированием в рамках теста и обновлены результаты.

+0

В вашей реализации отсутствует сбор дубликатов. –

+0

@ KARASZIIstván. Проверьте весь код ... есть три метода, в результате чего три разных теста. Последнее равно вашему решению. –

+0

Я проверил ваш код, поэтому я написал свой комментарий. Вы создали хэш с счетчиками, но вам нужно получить дубликаты из этого хэша, и этого не хватает в вашем тесте. –

Смежные вопросы