นับ, ขนาด, ความยาว…มีตัวเลือกมากเกินไปในรูบี?


140

ฉันไม่สามารถหาคำตอบที่ชัดเจนเกี่ยวกับเรื่องนี้และฉันต้องการให้แน่ใจว่าฉันเข้าใจในระดับ "n'th" :-)

    a = {"a" => "Hello", "b" => "โลก"}
    a.count # 2
    a.size # 2
    a.length # 2

    a = [10, 20]
    a.count # 2
    a.size # 2
    a.length # 2

ดังนั้นที่จะใช้? ถ้าฉันต้องการทราบว่ามีองค์ประกอบมากกว่าหนึ่งองค์ประกอบมันไม่สำคัญ แต่ฉันต้องการให้แน่ใจว่าฉันเข้าใจความแตกต่างที่แท้จริง สิ่งนี้ใช้กับอาร์เรย์ด้วย ฉันได้รับผลลัพธ์เดียวกัน

นอกจากนี้ฉันรู้ว่าการนับ / ขนาด / ความยาวมีความหมายต่างกันด้วย ActiveRecord ฉันสนใจทับทิมบริสุทธิ์ (1.92) ส่วนใหญ่ในตอนนี้ แต่ถ้าใครอยากพูดถึงความแตกต่างของ AR ก็น่าจะเป็นที่ชื่นชมเช่นกัน

ขอบคุณ!


5
ปรากฏการณ์ที่คุณพบบางครั้งเรียกว่าTMTOWTDI : มีมากกว่าหนึ่งวิธีที่ต้องทำ สโลแกนนี้มาจากชุมชน Perl และ Perl เป็นหนึ่งในอิทธิพลของทับทิม
Andrew Grimm

พวกนี้มักเป็นนามแฝงซึ่งกันและกัน มีวิธีหนึ่งที่คุณควรคำนึงถึง: Array#nitemsซึ่งจะคืนค่าจำนวนรายการที่ไม่ใช่ NIL ในอาร์เรย์ แต่ไม่สามารถใช้งานได้ใน Ruby 1.9 อีกต่อไป
Tilo

คำตอบ:


194

สำหรับอาร์เรย์และ hashes เป็นนามแฝงสำหรับsize lengthพวกเขามีความหมายเหมือนกันและทำสิ่งเดียวกัน

count มีความหลากหลายมากขึ้น - สามารถใช้องค์ประกอบหรือเพรดิเคตและนับเฉพาะรายการที่ตรงกัน

> [1,2,3].count{|x| x > 2 }
=> 1

ในกรณีที่คุณไม่ได้ระบุพารามิเตอร์เพื่อนับว่ามีผลเหมือนกับความยาวการโทร อาจมีความแตกต่างด้านประสิทธิภาพได้

เราสามารถเห็นได้จากซอร์สโค้ดสำหรับ Arrayว่าพวกเขาทำสิ่งเดียวกันเกือบทั้งหมด นี่คือรหัส C สำหรับการดำเนินการarray.length:

static VALUE
rb_ary_length(VALUE ary)
{
    long len = RARRAY_LEN(ary);
    return LONG2NUM(len);
}

และนี่คือส่วนที่เกี่ยวข้องจากการดำเนินการarray.count:

static VALUE
rb_ary_count(int argc, VALUE *argv, VALUE ary)
{
    long n = 0;

    if (argc == 0) {
        VALUE *p, *pend;

        if (!rb_block_given_p())
            return LONG2NUM(RARRAY_LEN(ary));

        // etc..
    }
}

รหัสสำหรับ The array.countไม่ได้ตรวจสอบพิเศษบาง LONG2NUM(RARRAY_LEN(ary))แต่ในท้ายที่สุดเรียกรหัสเดียวกันแน่นอน:

แฮช ( ซอร์สโค้ด ) ในทางกลับกันดูเหมือนจะไม่ใช้เวอร์ชันที่ดีที่สุดของตนเองcountดังนั้นการใช้งานจากEnumerable( ซอร์สโค้ด ) จะใช้ซึ่งวนซ้ำองค์ประกอบทั้งหมดและนับทีละรายการ

โดยทั่วไปฉันแนะนำให้ใช้length(หรือนามแฝงsize) แทนcountถ้าคุณต้องการทราบว่ามีองค์ประกอบทั้งหมดกี่รายการ


สำหรับ ActiveRecord นั้นมีความแตกต่างที่สำคัญ ตรวจสอบโพสต์นี้:


10

มีความแตกต่างที่สำคัญสำหรับแอปพลิเคชันซึ่งใช้ประโยชน์จากการเชื่อมต่อฐานข้อมูล

เมื่อคุณใช้ ORM จำนวนมาก (ActiveRecord, DataMapper เป็นต้น) ความเข้าใจทั่วไปคือ. ขนาดจะสร้างแบบสอบถามที่ขอรายการทั้งหมดจากฐานข้อมูล ('เลือก * จาก mytable') จากนั้นให้จำนวนรายการ ส่งผลให้ในขณะที่. จำนวนจะสร้างแบบสอบถามเดียว ('เลือกนับ (*) จาก mytable') ซึ่งเร็วกว่ามาก

เพราะ ORMs เหล่านี้แพร่หลายมากฉันทำตามหลักการของความประหลาดใจน้อยที่สุด โดยทั่วไปถ้าฉันมีบางอย่างในหน่วยความจำแล้วฉันจะใช้. ขนาดและถ้ารหัสของฉันจะสร้างคำขอไปยังฐานข้อมูล (หรือบริการภายนอกผ่านทาง API) ฉันใช้. นับ


1
counter_cacheสิ่งที่ต้องพิจารณาด้วยนี้คือ หากมีตารางfooและมี _many barคุณจะมีคอลัมน์ในfooชื่อbars_countที่ได้รับการอัปเดตทุกครั้งที่มีการbarสร้าง / ทำลาย การใช้foo.bars.sizeคือสิ่งที่ตรวจสอบคอลัมน์นั้น (โดยไม่ต้องสอบถามจริง ๆbars) foo.bars.countทำแบบสอบถามจริงซึ่งจะเอาชนะวัตถุประสงค์ของแคช
Dudo

7

ในกรณีส่วนใหญ่ (เช่นอาร์เรย์หรือString ) sizeเป็นนามแฝงlengthสำหรับ

countโดยปกติจะมาจากEnumerableและสามารถเลือกใช้เพรดิเคตบล็อกได้ ดังนั้นenumerable.count {cond}[คร่าว] (enumerable.select {cond}).length- แน่นอนว่ามันสามารถข้ามโครงสร้างกลางได้เนื่องจากต้องการเพียงจำนวนภาคที่เข้าคู่

หมายเหตุ: ฉันไม่แน่ใจว่าจะcount บังคับให้มีการประเมินการแจงนับถ้าบล็อกไม่ได้ระบุหรือถ้ามันลัดวงจรไปที่lengthถ้าเป็นไปได้

แก้ไข (และต้องขอบคุณคำตอบของ Mark!): count ไม่มีบล็อก (อย่างน้อยสำหรับอาร์เรย์) ไม่ได้บังคับให้มีการประเมินผล ฉันคิดว่าไม่มีพฤติกรรมอย่างเป็นทางการมัน "เปิด" สำหรับการใช้งานอื่น ๆ ถ้าบังคับให้ประเมินโดยไม่ต้องภาคแสดงเคยทำให้รู้สึกถึงความจริง


5

ฉันพบซอฟต์แวร์ที่ดีที่http://blog.hasmanythrough.com/2008/2/27/count-length-size

ใน ActiveRecord มีหลายวิธีในการค้นหาจำนวนเรคคอร์ดที่อยู่ในการเชื่อมโยงและมีความแตกต่างเล็กน้อยในการทำงาน

post.comments.count - กำหนดจำนวนองค์ประกอบด้วยคำสั่ง SQL COUNT คุณยังสามารถระบุเงื่อนไขเพื่อนับเฉพาะชุดย่อยขององค์ประกอบที่เกี่ยวข้อง (เช่น: เงื่อนไข => {: author_name => "josh"}) หากคุณตั้งค่าตัวนับที่แคชไว้ในการเชื่อมโยง #count จะส่งคืนค่าแคชนั้นแทนการเรียกใช้คิวรีใหม่

post.comments.length - นี่จะโหลดเนื้อหาของการเชื่อมโยงไปยังหน่วยความจำเสมอจากนั้นส่งคืนจำนวนองค์ประกอบที่โหลด โปรดทราบว่านี่จะไม่บังคับให้อัปเดตหากมีการโหลดการเชื่อมโยงก่อนหน้านี้และความคิดเห็นใหม่จะถูกสร้างขึ้นด้วยวิธีอื่น (เช่น Comment.create (... ) แทน post.comments.create (... ))

post.comments.size - การทำงานนี้เป็นการรวมกันของสองตัวเลือกก่อนหน้า หากมีการโหลดคอลเลกชันแล้วมันจะส่งคืนความยาวได้เช่นเดียวกับการโทร #length หากยังไม่ได้โหลดมันก็เหมือนกับการโทร #count

นอกจากนี้ฉันมีประสบการณ์ส่วนตัว:

<%= h(params.size.to_s) %> # works_like_that !
<%= h(params.count.to_s) %> # does_not_work_like_that !

2

เรามีหลายวิธีที่จะหาวิธีการหลายองค์ประกอบในอาร์เรย์เช่น.length, และ.count .sizeแต่มันเป็นเรื่องดีที่จะใช้มากกว่าarray.size array.countเพราะ.sizeประสิทธิภาพที่ดีขึ้น


1

การเพิ่มคำตอบของ Mark Byers ให้มากขึ้น ใน Ruby เมธอดarray.sizeคือ alias to to Array # length method ไม่มีความแตกต่างทางเทคนิคในการใช้วิธีใดวิธีหนึ่งในสองวิธีนี้ อาจเป็นไปได้ว่าคุณจะไม่เห็นความแตกต่างของประสิทธิภาพเช่นกัน อย่างไรก็ตาม, array.countยังทำงานเหมือนกัน แต่ด้วยฟังก์ชันพิเศษArray # count

มันสามารถใช้เพื่อรับจำนวนรวมขององค์ประกอบตามเงื่อนไขบางอย่าง การนับสามารถเรียกได้สามวิธี:

Array # count # ส่งคืนจำนวนองค์ประกอบใน Array

Array # count n # ส่งคืนจำนวนองค์ประกอบที่มีค่า n ใน Array

อาร์เรย์ # count {| ฉัน | i.even?} ส่งคืนการนับตามเงื่อนไขที่เรียกใช้ในแต่ละอาร์เรย์องค์ประกอบ

array = [1,2,3,4,5,6,7,4,3,2,4,5,6,7,1,2,4]

array.size     # => 17
array.length   # => 17
array.count    # => 17

ที่นี่ทั้งสามวิธีทำหน้าที่เดียวกัน อย่างไรก็ตามที่นี่เป็นที่ที่countน่าสนใจ

ให้เราบอกว่าฉันต้องการที่จะหาว่าองค์ประกอบของอาร์เรย์มีจำนวนเท่าไหร่ที่มีค่า2

array.count 2    # => 3

อาร์เรย์มีองค์ประกอบทั้งหมดสามองค์ประกอบที่มีค่าเป็น 2

ตอนนี้ฉันต้องการค้นหาองค์ประกอบอาร์เรย์ทั้งหมดที่มากกว่า 4

array.count{|i| i > 4}   # =>6

อาร์เรย์มีองค์ประกอบทั้งหมด 6 รายการซึ่ง> มากกว่า 4

ฉันหวังว่ามันจะให้ข้อมูลเกี่ยวกับcountวิธีการ

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