রুবি - ইতিমধ্যে একটি অ্যারে না হলে মার্জিতভাবে ভ্যারিয়েবলকে একটি অ্যারেতে রূপান্তর করুন


120

একটি অ্যারে দেওয়া, একটি একক উপাদান, বা শূন্যস্থান, একটি অ্যারে প্রাপ্ত - দ্বিতীয় দুটি যথাক্রমে একক উপাদান অ্যারে এবং একটি খালি অ্যারে।

আমি ভুল করে বুঝতে পারি রুবি এভাবে কাজ করবে:

[1,2,3].to_a  #= [1,2,3]     # Already an array, so no change
1.to_a        #= [1]         # Creates an array and adds element
nil.to_a      #= []          # Creates empty array

তবে আপনি যা পাবেন তা হ'ল:

[1,2,3].to_a  #= [1,2,3]         # Hooray
1.to_a        #= NoMethodError   # Do not want
nil.to_a      #= []              # Hooray

সুতরাং এটি সমাধান করার জন্য, আমাকে অন্য পদ্ধতিটি ব্যবহার করতে হবে, বা আমি যে সমস্ত ক্লাস ব্যবহার করতে চাইছি তার to_a পদ্ধতিটি সংশোধন করে মেটা প্রোগ্রাম করতে পারলাম - যা আমার পক্ষে কোনও বিকল্প নয়।

সুতরাং এটি একটি পদ্ধতি:

result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))

সমস্যা হ'ল এটি কিছুটা গণ্ডগোল। এটি করার একটি মার্জিত উপায় আছে? (যদি এই সমস্যাটি সমাধানের রুবি-ইশ উপায় হয় তবে আমি অবাক হয়ে যাব)


এটি কি অ্যাপ্লিকেশন আছে? এমনকি একটি অ্যারে রূপান্তর কেন?

রেলের অ্যাক্টিভেকর্ডে, কল করে বলুন, user.postsহয় পোস্টগুলির একটি অ্যারে, একটি একক পোস্ট, বা শূন্য করে দেবে। এর ফলাফলগুলি নিয়ে কাজ করে এমন পদ্ধতিগুলি লেখার সময়, এটি অনুমান করা সবচেয়ে সহজ যে পদ্ধতিটি একটি অ্যারে নেবে, যার শূন্য, এক বা অনেক উপাদান থাকতে পারে। উদাহরণ পদ্ধতি:

current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}

2
user.postsকখনও একটি পোস্ট ফেরত দেওয়া উচিত নয়। কমপক্ষে, আমি এটি কখনও দেখিনি।
সেরজিও টুলেন্টসিভ

1
আমি মনে করি আপনার প্রথম দুটি কোড ব্লকে আপনার ==পরিবর্তে বোঝানো উচিত =, তাই না?
প্যাট্রিক অসিটি


3
BTW, [1,2,3].to_aনেই না আসতে [[1,2,3]]! এটি ফিরে আসে [1,2,3]
প্যাট্রিক অসিটি

ধন্যবাদ প্যাডেল, প্রশ্ন আপডেট করবেন ... নিজের
মুখের মুখগুলি

উত্তর:


153

[*foo]বা Array(foo)বেশিরভাগ সময় কাজ করবে, তবে কিছু ক্ষেত্রে হ্যাশের মতো এটি এতে বিড়বিড় হয়।

Array([1, 2, 3])    # => [1, 2, 3]
Array(1)            # => [1]
Array(nil)          # => []
Array({a: 1, b: 2}) # => [[:a, 1], [:b, 2]]

[*[1, 2, 3]]    # => [1, 2, 3]
[*1]            # => [1]
[*nil]          # => []
[*{a: 1, b: 2}] # => [[:a, 1], [:b, 2]]

আমি কেবল হ্যাশের জন্য এমনকি এটির জন্য কাজ করতে পারি তা ভাবতে পারা যায় কোনও পদ্ধতিটিকে সংজ্ঞায়িত করা।

class Object; def ensure_array; [self] end end
class Array; def ensure_array; to_a end end
class NilClass; def ensure_array; to_a end end

[1, 2, 3].ensure_array    # => [1, 2, 3]
1.ensure_array            # => [1]
nil.ensure_array          # => []
{a: 1, b: 2}.ensure_array # => [{a: 1, b: 2}]

2
পরিবর্তে ensure_array, প্রসারিত করুনto_a
ড্যান গ্রাহন

9
@ স্ক্রিনম্যাট এটি এমন পদ্ধতিগুলিকে প্রভাবিত করবে যা আসল ব্যবহারের উপর নির্ভর করে to_a। উদাহরণস্বরূপ, {a: 1, b: 2}.each ...অন্যভাবে কাজ করবে।
সাওয়া

1
আপনি এই সিনট্যাক্স ব্যাখ্যা করতে পারেন? রুবির বহু বছরে আমি কখনই এই জাতীয় অনুরোধ করতে পারি নি। শ্রেণীর নামের উপর বন্ধনীগুলি কী করে? আমি এটি ডক্সে খুঁজে পাচ্ছি না।
মাস্তাব্লাস্টা

1
@ মাস্টব্লাস্টা অ্যারে (আরগ) টি_আর, তারপরে আর্গুমেন্টে কল করে একটি নতুন অ্যারে তৈরি করার চেষ্টা করে। এটি সরকারী রুবি ডক্সে নথিভুক্ত করা হয়েছে। আমি এ সম্পর্কে অবদীর "কনফিডেন্ট রুবি" বইটি থেকে শিখেছি।
mambo

2
@ ম্যাম্বো আমার প্রশ্ন পোস্ট করার পরে একসময় উত্তরটি খুঁজে পেলাম। কঠিন অংশটি হ'ল এটি অ্যারে বর্গের সাথে কিছুই করার নেই তবে এটি কার্নেল মডিউলটিতে একটি পদ্ধতি। ruby-doc.org/core-2.3.1/Kernel.html#method-i-Array
mastaBlasta

119

অ্যাক্টিভসপোর্ট (রেলস) সহ: Array.wrap

Array.wrap([1, 2, 3])     # => [1, 2, 3]
Array.wrap(1)             # => [1]
Array.wrap(nil)           # => []
Array.wrap({a: 1, b: 2})  # => [{:a=>1, :b=>2}]

আপনি যদি রেলগুলি ব্যবহার না করে থাকেন তবে আপনি রেলের উত্সের অনুরূপ নিজস্ব পদ্ধতি নির্ধারণ করতে পারেন ।

class Array
  def self.wrap(object)
    if object.nil?
      []
    elsif object.respond_to?(:to_ary)
      object.to_ary || [object]
    else
      [object]
    end
  end
end

12
class Array; singleton_class.send(:alias_method, :hug, :wrap); endঅতিরিক্ত নমনীয়তার জন্য।
rthbound

21

সবচেয়ে সহজ সমাধানটি ব্যবহার করা [foo].flatten(1)। অন্যান্য প্রস্তাবিত সমাধানগুলির বিপরীতে, এটি (নেস্টেড) অ্যারে, হ্যাশ এবং nil:

def wrap(foo)
  [foo].flatten(1)
end

wrap([1,2,3])         #= [1,2,3]
wrap([[1,2],[3,4]])   #= [[1,2],[3,4]]
wrap(1)               #= [1]
wrap(nil)             #= [nil]
wrap({key: 'value'})  #= [{key: 'value'}]

দুর্ভাগ্যক্রমে অন্যান্য পদ্ধতির তুলনায় এটির একটি গুরুতর পারফরম্যান্স সমস্যা রয়েছে। Kernel#Arrayঅর্থাত্ Array()এগুলির মধ্যে দ্রুততম test রুবি 2.5.1 তুলনা: অ্যারে (): 7936825.7 i / s। অ্যারে.রেপ: 4199036.2 i / s - 1.89x ধীর। মোড়ানো: 644030.4 i / s - 12.32x ধীর
ওয়াসিফ হোসেন


13

অ্যাক্টিভসপোর্ট (রেলস)

অ্যাক্টিভসপোর্ট এর জন্য একটি দুর্দান্ত পদ্ধতি আছে। এটি রেলগুলি বোঝাই করা হয়েছে, তাই এটি করার জন্য সর্বোত্তম উপায়টি অবজ্ঞাপূর্ণভাবে:

Array.wrap([1, 2, 3]) #=> [1, 2, 3]
Array.wrap(nil) #=> nil

স্প্ল্যাট (রুবি 1.9+)

স্প্ল্যাট অপারেটর ( *) একটি অ্যারে আন-অ্যারে করে, যদি এটি করতে পারে:

*[1,2,3] #=> 1, 2, 3 (notice how this DOES not have braces)

অবশ্যই, অ্যারে ব্যতীত, এটি অদ্ভুত জিনিসগুলি করে এবং আপনার "স্প্ল্যাট" জিনিসগুলি অ্যারেতে রাখা প্রয়োজন। এটি কিছুটা অদ্ভুত, তবে এর অর্থ:

[*[1,2,3]] #=> [1, 2, 3]
[*5] #=> [5]
[*nil] #=> []
[*{meh: "meh"}] #=> [[:meh, "meh"], [:meh2, "lol"]]

আপনার যদি অ্যাক্টিভসপোর্ট না থাকে তবে আপনি পদ্ধতিটি নির্ধারণ করতে পারেন:

class Array
    def self.wrap(object)
        [*object]
    end
end

Array.wrap([1, 2, 3]) #=> [1, 2, 3]
Array.wrap(nil) #=> nil

যদিও, আপনি যদি বড় অ্যারে, এবং কম অ-অ্যারে জিনিস রাখার পরিকল্পনা করেন তবে আপনি এটি পরিবর্তন করতে চাইতে পারেন - উপরের পদ্ধতিটি বড় অ্যারেগুলির সাথে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে বেড়ে যায় Over যাইহোক, আপনি পরিবর্তে এটি করতে চাইবেন:

class Array
    def self.wrap(object)
        object.is_a? Array ? object : [*object]
    end
end

Array.wrap([1, 2, 3]) #=> [1, 2, 3]
Array.wrap(nil) #=> [nil]

টেনারে অপারেটরের সাথে এবং ছাড়াও আমার কিছু মানদণ্ড রয়েছে।


বড় অ্যারেগুলির জন্য কাজ করবে না। SystemStackError: stack level too deep1 এম উপাদানগুলির জন্য (রুবি ২.২.৩)
denis.peplin

@ denis.peplin দেখে মনে হচ্ছে আপনি স্ট্যাকওভারফ্লো ত্রুটি পেয়েছেন: ডি - সত্যি বলতে কী হয়েছে তা আমি নিশ্চিত নই। দুঃখিত।
বেন

আমি সম্প্রতি Hash#values_at1 এম আর্গুমেন্ট (ব্যবহার করে splat) দিয়ে চেষ্টা করেছি এবং এটি একই ত্রুটি ছুঁড়েছে।
denis.peplin

@ denis.peplin এটি কি কাজ করে object.is_a? Array ? object : [*object]?
বেন অউবিন

1
Array.wrap(nil)রিটার্ন দেয় []না nil: /
আয়ারামোর

7

কেমন

[].push(anything).flatten

2
হ্যাঁ আমি মনে করি আমি [কিছু] ব্যবহার করে শেষ করেছি my আমার ক্ষেত্রে ফ্লাট করুন ... তবে সাধারণ ক্ষেত্রে এটি কোনও নেস্টেড অ্যারে কাঠামোকেও সমতল করবে
xxjjnn

1
[].push(anything).flatten(1)কাজ করবে! এটা নেস্টেড অ্যারে চ্যাপ্টা না!
xxjjnn

2

সুস্পষ্টভাবে উল্লেখ করার ঝুঁকি নিয়ে এবং এটি গ্রহ এবং আশেপাশের অঞ্চলে দেখা যায় না যে এটি সবচেয়ে সুস্বাদু সিনট্যাকটিক চিনি আর কখনও দেখা যায় নি, এই কোডটি আপনার বর্ণনা অনুযায়ী ঠিক তেমনটি করেছে বলে মনে হচ্ছে:

foo = foo.is_a?(Array) ? foo : foo.nil? ? [] : [foo]

1

আপনি অবজেক্টের অ্যারে পদ্ধতিটি ওভাররাইট করতে পারেন

class Object
    def to_a
        [self]
    end
end

সবকিছু অবজেক্টের উত্তরাধিকার সূত্রে প্রাপ্ত হয়, সুতরাং এখন_ সূর্যের নীচে সমস্ত কিছুর জন্য সংজ্ঞা দেওয়া হবে


3
নিন্দিত বানর প্যাচিং! তওবা করুন!
xxjjnn

1

আমি সমস্ত উত্তর দিয়েছি এবং বেশিরভাগ রুবি 2+ এ কাজ করে না

তবে ইলাদোর সবচেয়ে মার্জিত সমাধান অর্থাৎ

অ্যাক্টিভসপোর্ট (রেলস) সহ: অ্যারে.রেপ

অ্যারে.আর্যাপ ([1, 2, 3]) # => [1, 2, 3]

অ্যারে.আর্যাপ (1) # => [1]

অ্যারে.রেপ (শূন্য) # => []

অ্যারে.আর্যাপ ({a: 1, b: 2}) # => [{: a => 1,: বি => 2}]

দুঃখের বিষয় তবে এটি রুবি 2+ এর জন্যও কাজ করে না কারণ আপনি একটি ত্রুটি পাবেন

undefined method `wrap' for Array:Class

যাতে আপনার প্রয়োজন প্রয়োজন ঠিক করতে।

'অ্যাক্টিভ_সপোর্ট / অবমূল্যায়ন' প্রয়োজন

প্রয়োজন 'অ্যাক্টিভ_সপোর্ট / কোর_সেক্সট / অ্যারে / মোড়ক'


0

যেহেতু #to_aদুটি মূল সমস্যাযুক্ত ক্লাস ( Nilএবং Hash) এর জন্য পদ্ধতিটি ইতিমধ্যে বিদ্যমান রয়েছে , তাই কেবলমাত্র প্রসারিত করে বাকীগুলির জন্য একটি পদ্ধতি নির্ধারণ করুন Object:

class Object
    def to_a
        [self]
    end
end

এবং তারপরে আপনি যে কোনও বস্তুতে সহজেই সেই পদ্ধতিটি কল করতে পারেন:

"Hello world".to_a
# => ["Hello world"]
123.to_a
# => [123]
{a:1, b:2}.to_a
# => [[:a, 1], [:b, 2]] 
nil.to_a
# => []

5
আমি সত্যিই মনে করি একটি বাঁদর একটি মূল রুবি ক্লাসকে বিশেষত অবজেক্ট করে, এড়ানো উচিত। আমি অ্যাক্টিভসপোর্টকে একটি পাস দেব যদিও তা আমাকে ভন্ড মনে করে। @ সাওয়া দ্বারা উপরের সমাধানগুলি এর চেয়ে অনেক বেশি কার্যকর।
pho3nixf1re
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.