Mảng bao gồm giá trị nào từ mảng khác?


155

Cách hiệu quả nhất để kiểm tra xem một mảng có chứa phần tử nào từ mảng thứ hai không?

Hai ví dụ dưới đây, cố gắng trả lời câu hỏi có foodschứa bất kỳ yếu tố nào từ cheeses:

cheeses = %w(chedder stilton brie mozzarella feta haloumi reblochon)
foods = %w(pizza feta foods bread biscuits yoghurt bacon)

puts cheeses.collect{|c| foods.include?(c)}.include?(true)

puts (cheeses - foods).size < cheeses.size

Câu trả lời:


268
(cheeses & foods).empty?

Như Marc-André Lafortune đã nói trong các bình luận, &hoạt động theo thời gian tuyến tính trong khi any?+ include?sẽ là bậc hai. Đối với các tập dữ liệu lớn hơn, thời gian tuyến tính sẽ nhanh hơn. Đối với các tập dữ liệu nhỏ, any?+ include?có thể nhanh hơn như được hiển thị bởi câu trả lời của Lee Jarvis - có thể là do &phân bổ một Mảng mới trong khi một giải pháp khác thì không và hoạt động như một vòng lặp lồng đơn giản để trả về một boolean.


3
Khi kiểm tra xem một mảng có chứa một phần tử từ một mảng khác không, nó sẽ có ý nghĩa hơn để làm (pho mát & thực phẩm) .any? vì điều này trả về một giá trị thực nếu trên thực tế các mảng có chứa bất kỳ phần tử nào giống nhau không?
Ryan Francis

1
@RyanFrancis, tài liệu: any?: Phương pháp này trả về true nếu khối bao giờ trả về một giá trị khác hơn là sai hoặc không. empty?: Trả về true nếu self không chứa phần tử.
Nakilon

3
@Nakilon Tôi cũng bối rối tại sao câu trả lời không phải (cheeses & foods).any?là câu hỏi của OP: nếu có thực phẩm nào ở trong pho mát? Trong ví dụ của anh ấy, "feta" là cả hai, vì vậy kết quả phải đúng, phải không? Vậy tại sao phải kiểm tra .empty?trên ngã tư?
SuckerForMayhem

@SuckerForMayhem, vì câu hỏi của OP là "Nếu có là ... ?", Không chỉ là "Nếu có?". Nếu " là ... " bị bỏ qua, nó được coi là "Nếu có đúng không? " Và sẽ trả về Sai cho mảng như thế [false, false, false], trong khi rõ ràng nó không trống.
Nakilon

Có bất kỳ thực hiện trong cấp độ Activerecord?
Lee Chun Hoe

35

Làm thế nào về số lượng # bất kỳ?

>> cheeses = %w(chedder stilton brie mozzarella feta haloumi)
=> ["chedder", "stilton", "brie", "mozzarella", "feta", "haloumi"]
>> foods = %w(pizza feta foods bread biscuits yoghurt bacon)
=> ["pizza", "feta", "foods", "bread", "biscuits", "yoghurt", "bacon"]
>> foods.any? {|food| cheeses.include?(food) }
=> true

Kịch bản điểm chuẩn:

require "benchmark"
N = 1_000_000
puts "ruby version: #{RUBY_VERSION}"

CHEESES = %w(chedder stilton brie mozzarella feta haloumi).freeze
FOODS = %w(pizza feta foods bread biscuits yoghurt bacon).freeze

Benchmark.bm(15) do |b|
  b.report("&, empty?") { N.times { (FOODS & CHEESES).empty? } }
  b.report("any?, include?") { N.times { FOODS.any? {|food| CHEESES.include?(food) } } }
end

Kết quả:

ruby version: 2.1.9
                      user     system      total        real
&, empty?         1.170000   0.000000   1.170000 (  1.172507)
any?, include?    0.660000   0.000000   0.660000 (  0.666015)

Bạn có thể cải thiện điều này bằng cách biến cheesesthành một bộ.
akuhn

1
Chạy điểm chuẩn của riêng tôi ở đây trên ruby ​​2.2.7 và 2.3.4 và any?, include?là điểm nhanh nhất, đặt ra mức chậm nhất: gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497
Jared

4
Điểm chuẩn này bị sai lệch bởi ví dụ cụ thể được đề cập và không nhất thiết phải giữ trong trường hợp tổng quát hơn. Điều gì xảy ra nếu không có các yếu tố chung giữa hai mảng? Điều gì xảy ra nếu các mảng theo thứ tự khác nhau trên mỗi lần vượt qua? Nếu feta xuất hiện ở cuối cả hai mảng thì sao? Như Marc-André đã nêu, thiết lập giao lộ thực hiện theo thời gian tuyến tính, do đó, có ý nghĩa rằng nó có khả năng mở rộng hơn nhiều cho trường hợp chung, thay vì một ví dụ cụ thể được sử dụng hoàn toàn để làm rõ câu hỏi.
user2259664

22

Bạn có thể kiểm tra xem giao lộ có trống không.

cheeses = %w(chedder stilton brie mozzarella feta haloumi)
foods = %w(pizza feta foods bread biscuits yoghurt bacon)
foods & cheeses
=> ["feta"] 
(foods & cheeses).empty?
=> false

1
Set.new(cheeses).disjoint? Set.new(foods)

Ngoài ra, trong điểm chuẩn (không khoa học) của tôi, thiết lập tách rời chậm hơn đáng kể so với các phương pháp khác: gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497
Jared

1
Cảm ơn ý kiến ​​của bạn. Tôi không chắc tại sao nó không phải là Set.new nhưng tôi chỉ chỉnh sửa nó. Tôi đã thử điểm chuẩn hiệu suất của bạn trong 2.4.1. Của tôi đã làm tốt hơn nhưng vẫn không tốt nhất bằng cách sử dụng các bộ rời rạc có chứa nhiều từ hơn. Tôi đặt phiên bản của tôi trong một nhận xét về ý chính của bạn. Tôi cũng nghĩ disjoint?là rất thanh lịch, đặc biệt là so với "bất kỳ?, Bao gồm?". Các câu hỏi ban đầu đã hỏi về cả thanh lịch và hiệu quả.
davidkovsky

.to_setphương pháp có thể hữu ích ở đâycheeses.to_set.disjoint?(foods.to_set)
itnikolay

0
require "benchmark"
N = 1_000_000
puts "ruby version: #{RUBY_VERSION}"

CHEESES = %w(chedder stilton brie mozzarella feta haloumi).freeze
FOODS = %w(pizza feta foods bread biscuits yoghurt bacon).freeze

Benchmark.bm(15) do |b|
  b.report("&, empty?") { N.times { (FOODS & CHEESES).empty? } }  
  b.report("any?, include?") { N.times { FOODS.any? {|food| CHEESES.include?(food) } } }  
  b.report("disjoint?") { N.times { FOODS.to_set.disjoint? CHEESES.to_set }}
end  
                      user     system      total        real
&, empty?         0.751068   0.000571   0.751639 (  0.752745)
any?, include?    0.408251   0.000133   0.408384 (  0.408438)
disjoint?        11.616006   0.014806  11.630812 ( 11.637300)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.