บอกจุดสิ้นสุดของแต่ละวงในทับทิม


91

ถ้าฉันมีลูปเช่น

users.each do |u|
  #some code
end

โดยที่ผู้ใช้คือแฮชของผู้ใช้หลายคน อะไรคือตรรกะเงื่อนไขที่ง่ายที่สุดในการดูว่าคุณอยู่ในผู้ใช้คนสุดท้ายในแฮชผู้ใช้และต้องการเรียกใช้รหัสเฉพาะสำหรับผู้ใช้คนสุดท้ายเท่านั้น

users.each do |u|
  #code for everyone
  #conditional code for last user
    #code for the last user
  end
end

คุณหมายถึงแฮชจริงๆหรือ? การสั่งซื้อแฮชนั้นไม่น่าเชื่อถือเสมอไป (ขึ้นอยู่กับว่าคุณเพิ่มสิ่งต่างๆลงในแฮชอย่างไรและคุณใช้ทับทิมรุ่นใด) การสั่งซื้อรายการ 'สุดท้าย' ที่ไม่น่าเชื่อถือจะไม่สอดคล้องกัน รหัสในคำถามและคำตอบที่คุณได้รับนั้นเหมาะสมกว่าสำหรับอาร์เรย์หรือแจกแจงได้ ตัวอย่างเช่นแฮชไม่มีeach_with_indexหรือlastวิธีการ
Shadwell

1
Hashผสมใน Enumerable each_with_indexจึงไม่ต้อง แม้ว่าจะไม่เรียงลำดับคีย์แฮช แต่ตรรกะประเภทนี้จะเกิดขึ้นตลอดเวลาเมื่อแสดงผลมุมมองโดยที่รายการสุดท้ายอาจแสดงแตกต่างกันไม่ว่าจะเป็น "สุดท้าย" ในแง่ที่มีความหมายของข้อมูลหรือไม่ก็ตาม
Raphomet

แน่นอนว่าค่อนข้างถูกต้องมีแฮชeach_with_indexขอโทษ ใช่ฉันเห็นว่ามันจะเกิดขึ้น เพียงแค่พยายามชี้แจงคำถาม โดยส่วนตัวแล้วคำตอบที่ดีที่สุดสำหรับฉันคือการใช้.lastแต่ไม่ได้ใช้กับแฮชเฉพาะอาร์เรย์
Shadwell

ซ้ำตัวบ่งชี้ Magic First และ Last ใน Loop ใน Ruby / Rails? นอกเหนือจากนี้เป็นแฮชมากกว่าอาร์เรย์
Andrew Grimm

1
@ แอนดรูว์ยอมรับว่ามันเกี่ยวข้องกันโดยสิ้นเชิงอย่างไรก็ตามคำตอบเล็ก ๆ น้อย ๆ ที่ยอดเยี่ยมของ meagars แสดงให้เห็นว่ามันไม่ใช่การหลอกลวงอย่างแน่นอน
Sam Saffron

คำตอบ:


148
users.each_with_index do |u, index|
  # some code
  if index == users.size - 1
    # code for the last user
  end
end

4
ปัญหานี้คือเงื่อนไขจะถูกเรียกใช้ในแต่ละครั้ง ใช้.lastนอกลูป
bcackerman

3
ฉันแค่เพิ่มว่าถ้าคุณทำซ้ำในแฮชคุณต้องเขียนว่า:users.each_with_index do |(key, value), index| #your code end
HUB

ฉันรู้ว่ามันไม่ใช่คำถามเดียวกันทั้งหมด แต่รหัสนี้ใช้งานได้ดีกว่าฉันคิดว่าถ้าคุณต้องการทำบางสิ่งกับทุกคน แต่เป็นผู้ใช้คนสุดท้ายดังนั้นฉันจึงโหวตให้เพราะนั่นคือสิ่งที่ฉันกำลังมองหา
WhiteTiger

38

หากเป็นอย่างใดอย่างหนึ่ง / หรือสถานการณ์ที่คุณกำลังใช้โค้ดกับทุกคนยกเว้นผู้ใช้คนสุดท้ายและโค้ดที่ไม่ซ้ำกันกับผู้ใช้คนสุดท้ายเท่านั้นวิธีแก้ปัญหาอื่น ๆ อาจเหมาะสมกว่า

อย่างไรก็ตามดูเหมือนว่าคุณจะใช้รหัสเดียวกันสำหรับผู้ใช้ทุกคนและรหัสเพิ่มเติมบางอย่างสำหรับผู้ใช้คนสุดท้าย หากเป็นเช่นนั้นสิ่งนี้ดูเหมือนจะถูกต้องมากขึ้นและระบุเจตนาของคุณได้ชัดเจนยิ่งขึ้น:

users.each do |u|
  #code for everyone
end

users.last.do_stuff() # code for last user

2
+1 หากไม่ต้องการเงื่อนไขหากเหมาะสม (แน่นอนฉันมาที่นี่)
Jeremy

@meagar จะไม่วนซ้ำผู้ใช้สองครั้งนี้หรือ
มด

@ant ไม่มีหนึ่งลูปและหนึ่งการโทร.lastที่ไม่มีอะไรเกี่ยวข้องกับการวนซ้ำ
meagar

@meagar เพื่อที่จะไปถึงสุดท้ายมันจะไม่วนซ้ำภายในจนกว่าองค์ประกอบสุดท้าย? มันมีวิธีการเข้าถึงองค์ประกอบโดยตรงโดยไม่ต้องวนซ้ำ?
มด

1
@ant .lastไม่มีไม่มีการวนลูปภายในส่วนร่วมในการ คอลเลกชันได้รับการสร้างอินสแตนซ์แล้วมันเป็นเพียงการเข้าถึงอาร์เรย์แบบง่ายๆ แม้ว่าคอลเลกชันจะยังไม่ได้โหลด (เช่นเดียวกับในนั้นก็ยังคงเป็นความสัมพันธ์ ActiveRecord ที่lastไม่ได้รับน้ำ) ก็ยังไม่เคยวนซ้ำเพื่อรับค่าสุดท้ายซึ่งจะไม่มีประสิทธิภาพอย่างมาก เพียงแค่ปรับเปลี่ยนแบบสอบถาม SQL เพื่อส่งคืนระเบียนสุดท้าย ที่กล่าวว่าคอลเลกชันนี้ได้รับการโหลดโดยเพื่อให้มีความซับซ้อนมากขึ้นไม่เกี่ยวข้องกับกว่าถ้าคุณไม่ได้ทำ.each x = [1,2,3]; x.last
meagar

20

ฉันคิดว่าแนวทางที่ดีที่สุดคือ:

users.each do |u|
  #code for everyone
  if u.equal?(users.last)
    #code for the last user
  end
end

22
ปัญหาเกี่ยวกับคำตอบนี้คือหากผู้ใช้คนสุดท้ายเกิดขึ้นก่อนหน้านี้ในรายการรหัสเงื่อนไขจะถูกเรียกหลายครั้ง
evanrmurphy

1
คุณต้องใช้u.equal?(users.last)การequal?วิธีการเปรียบเทียบ object_id ที่ไม่คุ้มค่าของวัตถุ แต่จะใช้ไม่ได้กับสัญลักษณ์และตัวเลข
Nafaa Boutefer



3

บางครั้งฉันพบว่ามันเป็นการดีกว่าที่จะแยกตรรกะออกเป็นสองส่วนส่วนหนึ่งสำหรับผู้ใช้ทั้งหมดและอีกส่วนสำหรับส่วนสุดท้าย ดังนั้นฉันจะทำสิ่งนี้:

users[0...-1].each do |user|
  method_for_all_users user
end

method_for_all_users users.last
method_for_last_user users.last

3

คุณสามารถใช้วิธีการของ @ meager ได้เช่นกันสำหรับ / หรือสถานการณ์โดยที่คุณกำลังใช้โค้ดกับทุกคนยกเว้นผู้ใช้คนสุดท้ายจากนั้นโค้ดที่ไม่ซ้ำกันกับผู้ใช้คนสุดท้ายเท่านั้น

users[0..-2].each do |u|
  #code for everyone except the last one, if the array size is 1 it gets never executed
end

users.last.do_stuff() # code for last user

วิธีนี้คุณไม่จำเป็นต้องมีเงื่อนไข!


@BeniBela ไม่ใช่ [-1] เป็นองค์ประกอบสุดท้าย ไม่มี [-0] วินาทีสุดท้ายคือ [-2]
coderuby

users[0..-2]users[0...-1]ถูกต้องตามที่เป็นอยู่ สังเกตตัวดำเนินการช่วงต่างๆ..เทียบกับ...ดูที่stackoverflow.com/a/9690992/67834
Eliot Sykes

2

อีกวิธีหนึ่งคือการช่วยเหลือจาก StopIteration:

user_list = users.each

begin
  while true do
    user = user_list.next
    user.do_something
  end
rescue StopIteration
  user.do_something
end

5
นี่ไม่ใช่วิธีแก้ปัญหาที่ดีสำหรับปัญหานี้ ไม่ควรใช้ข้อยกเว้นในทางที่ผิดสำหรับการควบคุมการไหลอย่างง่ายสำหรับสถานการณ์พิเศษ
meagar

@meagar นี่เกือบจะเจ๋งแล้ว ผมยอมรับว่าunrescuedข้อยกเว้นหรือคนที่จะต้องมีการส่งผ่านไปถึงวิธีการที่สูงขึ้นเท่านั้นควรจะเป็นสำหรับสถานการณ์พิเศษ อย่างไรก็ตามนี่เป็นวิธีที่เรียบร้อย (และเห็นได้ชัดเท่านั้น) ในการเข้าถึงความรู้ดั้งเดิมของทับทิมเกี่ยวกับจุดที่ตัววนซ้ำสิ้นสุดลง หากมีวิธีอื่นที่เป็นที่ต้องการแน่นอน ปัญหาที่แท้จริงเพียงอย่างเดียวที่ฉันใช้กับสิ่งนี้คือดูเหมือนว่าจะข้ามไปและไม่ทำอะไรเลยสำหรับรายการแรก การแก้ไขที่จะนำมันไปเหนือขอบเขตของความยุ่งเหยิง
Adamantish

2
@meagar ขออภัยสำหรับ "การโต้แย้งจากผู้มีอำนาจ" แต่ Matz ไม่เห็นด้วยกับคุณ ในความเป็นจริงStopIterationถูกออกแบบมาเพื่อเหตุผลที่แม่นยำในการจัดการการออกจากลูป จากหนังสือของ Matz: "สิ่งนี้อาจดูผิดปกติ - มีการเพิ่มข้อยกเว้นสำหรับเงื่อนไขการยุติที่คาดไว้แทนที่จะเป็นเหตุการณ์ที่ไม่คาดคิดและเป็นเหตุการณ์พิเศษ ( StopIterationเป็นลูกหลานของStandardErrorและIndexErrorโปรดทราบว่าเป็นหนึ่งในคลาสยกเว้นเดียวที่ไม่มีคำว่า “ error” ในชื่อ) Ruby ตามด้วย Python ในเทคนิคการวนซ้ำภายนอกนี้ (more ... )
BobRodes

(... ) โดยถือว่าการสิ้นสุดลูปเป็นข้อยกเว้นทำให้ตรรกะการวนซ้ำของคุณง่ายมาก ไม่จำเป็นต้องตรวจสอบค่าส่งคืนของค่าnextการสิ้นสุดการทำซ้ำแบบพิเศษและไม่จำเป็นต้องเรียกเพรดิเคตบางประเภทnext?ก่อนที่จะเรียกnext"
BobRodes

1
@ adamantish ควรสังเกตว่าloop doมีนัยrescueเมื่อพบ a StopIteration; ใช้เฉพาะเมื่อทำซ้ำEnumeratorวัตถุภายนอก loop do; my_enum.next; endจะวนซ้ำmy_enumและออกในตอนท้าย ไม่จำเป็นต้องใส่ที่rescue StopIterationนั่น (คุณต้องทำถ้าคุณใช้whileหรือuntil)
BobRodes

0

ไม่มีวิธีสุดท้ายสำหรับการแฮชสำหรับทับทิมบางเวอร์ชัน

h = { :a => :aa, :b => :bb }
last_key = h.keys.last
h.each do |k,v|
    puts "Put last key #{k} and last value #{v}" if last_key == k
end

เป็นคำตอบที่ช่วยเพิ่มคำตอบของคนอื่นหรือไม่? โปรดโพสต์คำตอบที่กล่าวถึงวิธี 'สุดท้าย' และคุณเสนออะไรเพื่อเอาชนะปัญหานี้
Artemix

สำหรับ Ruby เวอร์ชันที่ไม่มี a lastชุดของคีย์จะไม่เรียงลำดับดังนั้นคำตอบนี้จะแสดงผลลัพธ์ที่ผิด / สุ่ม
meagar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.