ผนวกวัตถุไปยังรายการใน R ในเวลาคงที่ตัดจำหน่าย O (1)?


245

หากฉันมีรายการ R บางรายการmylistคุณสามารถเพิ่มรายการต่อท้ายobjได้เช่น:

mylist[[length(mylist)+1]] <- obj

แต่แน่นอนว่ามีบางวิธีที่กะทัดรัดกว่า เมื่อฉันใหม่ที่ R ฉันพยายามเขียนlappend()ดังนี้:

lappend <- function(lst, obj) {
    lst[[length(lst)+1]] <- obj
    return(lst)
}

แต่แน่นอนว่าไม่ได้ทำงานเนื่องจากความหมายของการโทรด้วยชื่อของ R ( lstถูกคัดลอกอย่างมีประสิทธิภาพเมื่อมีการโทรดังนั้นการเปลี่ยนแปลงlstจะไม่สามารถมองเห็นได้นอกขอบเขตของlappend()ฉันรู้ว่าคุณสามารถแฮ็คสภาพแวดล้อมในฟังก์ชัน R เพื่อเข้าถึงภายนอก ขอบเขตของฟังก์ชั่นของคุณและกลายสภาพแวดล้อมการโทร แต่ดูเหมือนว่าค้อนขนาดใหญ่ที่จะเขียนฟังก์ชั่นผนวกง่าย

ใครช่วยแนะนำวิธีที่สวยงามกว่านี้ได้ไหม คะแนนโบนัสหากมันใช้ได้กับทั้งเวกเตอร์และลิสต์


5
R มีลักษณะข้อมูลที่เปลี่ยนแปลงไม่ได้ซึ่งมักพบในภาษาที่ใช้งานได้เกลียดที่จะพูดแบบนี้ แต่ฉันคิดว่าคุณต้องจัดการกับมัน มันมีข้อดีและข้อเสียของมัน
Dan

เมื่อคุณพูดว่า "call-by-name" คุณหมายถึง "call-by-value" จริงเหรอ?
เคนวิลเลียมส์

7
ไม่ไม่ใช่การโทรตามค่ามิฉะนั้นจะไม่เป็นปัญหา R ใช้การโทรตามความต้องการจริง ๆ ( en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need )
Nick

4
ความคิดที่ดีคือการจัดสรร vector / list ของคุณล่วงหน้า: N = 100 mylist = vector ('list', N) สำหรับ (i in 1: N) {#mylist [[i]] = ... } หลีกเลี่ยงการเติบโต 'objects ใน R.
Fernando

ฉันบังเอิญพบคำตอบที่นี่stackoverflow.com/questions/17046336/…จึงยากที่จะใช้อัลกอริทึมที่ง่ายมาก ๆ !
KH Kim

คำตอบ:


255

หากเป็นรายการสตริงให้ใช้c()ฟังก์ชัน:

R> LL <- list(a="tom", b="dick")
R> c(LL, c="harry")
$a
[1] "tom"

$b
[1] "dick"

$c
[1] "harry"

R> class(LL)
[1] "list"
R> 

มันใช้ได้กับเวกเตอร์ด้วยดังนั้นฉันจะได้คะแนนโบนัสได้อย่างไร

แก้ไข (2015-Feb-01):โพสต์นี้จะเกิดขึ้นในวันเกิดที่ห้าของมัน ผู้อ่านที่ใจดีบางคนยังคงทำข้อบกพร่องซ้ำ ๆ ซ้ำ ๆ ดังนั้นทุกคนจะเห็นความคิดเห็นบางส่วนด้านล่าง หนึ่งข้อเสนอแนะสำหรับlistประเภท:

newlist <- list(oldlist, list(someobj))

โดยทั่วไปแล้วประเภท R สามารถทำให้ยากที่จะมีสำนวนเดียวและหนึ่งสำหรับทุกประเภทและการใช้งาน


19
นี่ไม่ได้ผนวก ... มันเชื่อมต่อกัน LLจะยังคงมีสององค์ประกอบหลังจากC(LL, c="harry")เรียกว่า
Nick

27
เพียงแค่มอบหมายเพื่อ LL <- c(LL, c="harry")LL:
Dirk Eddelbuettel

51
ใช้งานได้กับสตริงเท่านั้น ถ้า a, b และ c เป็นจำนวนเต็มเวกเตอร์, พฤติกรรมนั้นแตกต่างอย่างสิ้นเชิง
Alexandre Rademaker

8
@Dirk: คุณมี parens ซ้อนกันแตกต่างจากฉัน โทรของฉันจะc()มี 2 ข้อโต้แย้ง: รายการฉันพยายามที่จะผนวกกับคือและรายการที่ฉันพยายามที่จะผนวกคือlist(a=3, b=c(4, 5)) c=c(6, 7)หากคุณใช้วิธีการของฉันคุณจะเห็นว่ามี2รายการในรายการต่อท้าย ( 6และ7มีชื่อc1และc2) แทนที่จะเป็นเวกเตอร์ 2 องค์ประกอบcเดียวที่ตั้งชื่อตามที่ตั้งใจไว้อย่างชัดเจน!
j_random_hacker

7
ดังนั้นข้อสรุปmylist <- list(mylist, list(obj))คืออะไร? ถ้าใช่มันเป็นการดีที่จะแก้ไขคำตอบ
Matthew

96

OP (ในการแก้ไขคำถามที่อัปเดตเมื่อเดือนเมษายน 2555) มีความสนใจที่จะรู้ว่ามีวิธีเพิ่มรายการในเวลาคงที่ที่ถูกตัดจำหน่ายหรือไม่เช่นสามารถทำได้ด้วยvector<>คอนเทนเนอร์C ++ คำตอบที่ดีที่สุดในตอนนี้จะแสดงเฉพาะเวลาดำเนินการสัมพัทธ์สำหรับวิธีแก้ปัญหาต่าง ๆ ที่กำหนดปัญหาที่มีขนาดคงที่ แต่ไม่ได้ระบุถึงประสิทธิภาพของอัลกอริทึมของโซลูชันต่างๆโดยตรง ความคิดเห็นด้านล่างคำตอบมากมายพูดคุยเกี่ยวกับประสิทธิภาพของอัลกอริทึมของการแก้ปัญหาบางอย่าง แต่ในทุกกรณีจนถึงปัจจุบัน (ณ เดือนเมษายน 2015) พวกเขาได้ข้อสรุปที่ผิด

จับประสิทธิภาพขั้นตอนลักษณะการเจริญเติบโตทั้งในเวลา (เวลาการดำเนินการ) หรือพื้นที่ (จำนวนหน่วยความจำบริโภค) ขนาดปัญหาเติบโต การรันการทดสอบประสิทธิภาพสำหรับโซลูชันที่หลากหลายเนื่องจากปัญหาขนาดคงที่ไม่ได้ระบุอัตราการเติบโตของโซลูชันต่าง ๆ OP มีความสนใจที่จะรู้ว่ามีวิธีการผนวกวัตถุเข้ากับรายการ R ใน "เวลาคงที่ที่ตัดจำหน่าย" หรือไม่ นั่นหมายความว่าอย่างไร? หากต้องการอธิบายก่อนอื่นให้ฉันอธิบาย "เวลาคงที่":

  • ค่าคงที่หรือO (1) :

    หากเวลาที่ต้องใช้ในการทำงานยังคงเท่ากับขนาดของปัญหาเพิ่มขึ้นเป็นสองเท่าเราจะบอกว่าอัลกอริทึมนั้นมีการเติบโตของเวลาคงที่หรือระบุไว้ในสัญกรณ์ "Big O" แสดงการเติบโตของเวลา O (1) เมื่อ OP บอกว่าเวลาคงที่ "ตัดจำหน่าย" เขาหมายถึง "ในระยะยาว" ... นั่นคือถ้าการดำเนินการครั้งเดียวใช้เวลานานกว่าปกติมาก (เช่นถ้าบัฟเฟอร์ที่จัดสรรล่วงหน้าหมดแล้วและบางครั้งจำเป็นต้องปรับขนาดให้ใหญ่ขึ้น) ขนาดบัฟเฟอร์) ตราบใดที่ประสิทธิภาพเฉลี่ยในระยะยาวเป็นเวลาคงที่เราจะยังคงเรียกมันว่า O (1)

    สำหรับการเปรียบเทียบฉันจะอธิบาย "เวลาเชิงเส้น" และ "เวลากำลังสอง":

  • การเติบโตเชิงเส้นหรือO (n) :

    หากเวลาที่ต้องใช้ในการทำงานที่กำหนดเพิ่มขึ้นเป็นสองเท่าเมื่อขนาดของปัญหาเพิ่มขึ้นเป็นสองเท่าเราจะบอกว่าอัลกอริทึมนั้นมีเวลาเชิงเส้นหรือการเติบโตO (n)

  • กำลังสองหรือการเจริญเติบโตO (n 2 ) :

    หากเวลาที่ต้องใช้ในการดำเนินงานที่กำหนดเพิ่มขึ้นด้วยกำลังสองของขนาดของปัญหาพวกเขาบอกว่าอัลกอริธึมแสดงเวลากำลังสองหรือการเติบโตO (n 2 )

อัลกอริธึมมีประสิทธิภาพอื่น ๆ อีกมากมาย ฉันชอบบทความ Wikipediaสำหรับการอภิปรายเพิ่มเติม

ฉันขอบคุณ @CronAcronis สำหรับคำตอบของเขาเนื่องจากฉันยังใหม่กับ R และมันดีที่มีบล็อคโค้ดที่สร้างขึ้นอย่างสมบูรณ์สำหรับการวิเคราะห์ประสิทธิภาพของโซลูชันต่างๆที่นำเสนอในหน้านี้ ฉันยืมรหัสของเขาสำหรับการวิเคราะห์ของฉันซึ่งฉันซ้ำ (ห่อในฟังก์ชั่น) ด้านล่าง:

library(microbenchmark)
### Using environment as a container
lPtrAppend <- function(lstptr, lab, obj) {lstptr[[deparse(substitute(lab))]] <- obj}
### Store list inside new environment
envAppendList <- function(lstptr, obj) {lstptr$list[[length(lstptr$list)+1]] <- obj} 
runBenchmark <- function(n) {
    microbenchmark(times = 5,  
        env_with_list_ = {
            listptr <- new.env(parent=globalenv())
            listptr$list <- NULL
            for(i in 1:n) {envAppendList(listptr, i)}
            listptr$list
        },
        c_ = {
            a <- list(0)
            for(i in 1:n) {a = c(a, list(i))}
        },
        list_ = {
            a <- list(0)
            for(i in 1:n) {a <- list(a, list(i))}
        },
        by_index = {
            a <- list(0)
            for(i in 1:n) {a[length(a) + 1] <- i}
            a
        },
        append_ = { 
            a <- list(0)    
            for(i in 1:n) {a <- append(a, i)} 
            a
        },
        env_as_container_ = {
            listptr <- new.env(parent=globalenv())
            for(i in 1:n) {lPtrAppend(listptr, i, i)} 
            listptr
        }   
    )
}

ผลลัพธ์ที่โพสต์โดย @CronAcronis ดูเหมือนจะแนะนำว่าa <- list(a, list(i))วิธีนี้เร็วที่สุดอย่างน้อยสำหรับขนาดของปัญหาที่ 10,000 แต่ผลลัพธ์สำหรับขนาดของปัญหาเดียวไม่ได้ระบุการเติบโตของโซลูชัน ด้วยเหตุนี้เราต้องดำเนินการทดสอบการทำโปรไฟล์อย่างน้อยสองครั้งด้วยขนาดของปัญหาที่แตกต่างกัน:

> runBenchmark(2e+3)
Unit: microseconds
              expr       min        lq      mean    median       uq       max neval
    env_with_list_  8712.146  9138.250 10185.533 10257.678 10761.33 12058.264     5
                c_ 13407.657 13413.739 13620.976 13605.696 13790.05 13887.738     5
             list_   854.110   913.407  1064.463   914.167  1301.50  1339.132     5
          by_index 11656.866 11705.140 12182.104 11997.446 12741.70 12809.363     5
           append_ 15986.712 16817.635 17409.391 17458.502 17480.55 19303.560     5
 env_as_container_ 19777.559 20401.702 20589.856 20606.961 20939.56 21223.502     5
> runBenchmark(2e+4)
Unit: milliseconds
              expr         min         lq        mean    median          uq         max neval
    env_with_list_  534.955014  550.57150  550.329366  553.5288  553.955246  558.636313     5
                c_ 1448.014870 1536.78905 1527.104276 1545.6449 1546.462877 1558.609706     5
             list_    8.746356    8.79615    9.162577    8.8315    9.601226    9.837655     5
          by_index  953.989076 1038.47864 1037.859367 1064.3942 1065.291678 1067.143200     5
           append_ 1634.151839 1682.94746 1681.948374 1689.7598 1696.198890 1706.683874     5
 env_as_container_  204.134468  205.35348  208.011525  206.4490  208.279580  215.841129     5
> 

ก่อนอื่นคำเกี่ยวกับค่า min / lq / mean / median / uq / max: เนื่องจากเรากำลังทำภารกิจเดียวกันที่แน่นอนสำหรับการวิ่ง 5 ครั้งในโลกอุดมคติเราคาดหวังว่ามันจะเหมือนกันทุกประการ จำนวนเวลาสำหรับการวิ่งแต่ละครั้ง แต่การรันครั้งแรกนั้นมักจะเอนเอียงไปสู่เวลาที่นานขึ้นเนื่องจากรหัสที่เรากำลังทดสอบยังไม่ได้โหลดลงในแคชของ CPU หลังจากการเรียกใช้ครั้งแรกเราคาดว่าเวลาจะค่อนข้างคงที่ แต่บางครั้งรหัสของเราอาจถูกขับออกจากแคชเนื่องจากการขัดจังหวะการจับเวลาเห็บหรือการขัดจังหวะของฮาร์ดแวร์อื่น ๆ ที่ไม่เกี่ยวข้องกับรหัสที่เรากำลังทดสอบ โดยการทดสอบโค้ดขนาด 5 ครั้งเราอนุญาตให้โหลดโค้ดลงในแคชในระหว่างการเรียกใช้ครั้งแรกและจากนั้นให้แต่ละส่วนย่อย 4 มีโอกาสทำงานให้เสร็จโดยไม่มีการรบกวนจากเหตุการณ์ภายนอก สำหรับเหตุผลนี้,

โปรดทราบว่าฉันเลือกที่จะเรียกใช้ครั้งแรกด้วยขนาดปัญหา 2000 และ 20,000 ดังนั้นขนาดปัญหาของฉันเพิ่มขึ้น 10 เท่าจากการทำงานครั้งแรกเป็นครั้งที่สอง

ประสิทธิภาพของการlistแก้ปัญหา: O (1) (เวลาคงที่)

ก่อนอื่นเรามาดูการเติบโตของlistโซลูชั่นเนื่องจากเราสามารถบอกได้ทันทีว่ามันเป็นทางออกที่เร็วที่สุดในการทำโปรไฟล์ทั้งสอง: ในการวิ่งครั้งแรกใช้เวลา 854 ไมโครวินาที (0.854 มิลลิวินาที) เพื่อดำเนินงานผนวก 2000 ในการรันครั้งที่สองใช้เวลา 8.746 มิลลิวินาทีในการดำเนินการ 20,000 งาน "ผนวก" ผู้สังเกตการณ์ไร้เดียงสาจะพูดว่า"อ่าlistวิธีแก้ปัญหาแสดงการเติบโตของ O (n) เนื่องจากขนาดของปัญหาเพิ่มขึ้นเป็นสิบเท่าดังนั้นเวลาที่ต้องใช้ในการทดสอบจึงเป็นเช่นนั้น" ปัญหาของการวิเคราะห์นั้นคือสิ่งที่ OP ต้องการคืออัตราการเติบโตของการแทรกวัตถุเดียวไม่ใช่อัตราการเติบโตของปัญหาโดยรวม เมื่อรู้แล้วมันก็ชัดเจนแล้วว่าlist วิธีการแก้ปัญหาให้สิ่งที่ OP ต้องการ: วิธีการผนวกวัตถุเข้ากับรายการในเวลา O (1)

ประสิทธิภาพของโซลูชั่นอื่น ๆ

ไม่มีวิธีแก้ปัญหาอื่นใดที่ใกล้เคียงกับความเร็วของการlistแก้ปัญหา แต่เป็นข้อมูลที่จะตรวจสอบได้

โซลูชันอื่น ๆ ส่วนใหญ่ดูเหมือนจะเป็น O (n) ในประสิทธิภาพ ตัวอย่างเช่นby_indexโซลูชันซึ่งเป็นโซลูชันที่ได้รับความนิยมอย่างมากตามความถี่ที่ฉันพบในโพสต์ SO อื่น ๆ ใช้เวลา 11.6 มิลลิวินาทีในการผนวกวัตถุ 2,000 รายการและ 953 มิลลิวินาทีเพื่อผนวกสิบวัตถุนั้น เวลาโดยรวมของปัญหาเพิ่มขึ้น 100 เท่าดังนั้นผู้สังเกตการณ์ไร้เดียงสาอาจพูดว่า"อ้อby_indexวิธีแก้ปัญหาแสดงการเติบโตของ O (n 2 ) เนื่องจากขนาดของปัญหาเพิ่มขึ้นสิบเท่าเวลาที่ต้องใช้ในการทดสอบเพิ่มขึ้น คูณด้วย 100 "เมื่อก่อนการวิเคราะห์นี้มีข้อบกพร่องเนื่องจาก OP มีความสนใจในการเติบโตของการแทรกวัตถุเดียว หากเราหารการเติบโตของเวลาโดยรวมด้วยการเพิ่มขนาดของปัญหาเราพบว่าการเพิ่มเวลาของการต่อท้ายวัตถุเพิ่มขึ้นเพียง 10 เท่านั้นไม่ใช่ 100 ซึ่งตรงกับการเติบโตของขนาดby_indexปัญหาวิธีการแก้ปัญหาคือ O (n) ไม่มีโซลูชันที่แสดงรายการซึ่งแสดงการเติบโต O (n 2 ) สำหรับการผนวกวัตถุเดียว


1
ถึงผู้อ่าน: โปรดอ่านคำตอบของ JanKanis ซึ่งเป็นส่วนขยายที่เป็นประโยชน์อย่างมากต่อการค้นพบของฉันและดำดิ่งลงบนค่าใช้จ่ายของโซลูชั่นต่างๆเนื่องจากการทำงานภายในของการนำ C ไปใช้ของ R.
phonetagger

4
ไม่แน่ใจว่าตัวเลือกรายการใช้สิ่งที่จำเป็น:> ความยาว (c (c (c (รายการ (1)), รายการ (2)), รายการ (3))) [1] 3> ความยาว (รายการ (รายการ (รายการ (รายการ) (รายการ (1)) รายการ (2)) รายการ (3))) [1] 2. ดูเหมือนรายการที่ซ้อนกัน
Picarus

@Picarus - ฉันคิดว่าคุณพูดถูก ฉันไม่ได้ทำงานกับ R อีกต่อไป แต่โชคดีที่ JanKanis โพสต์คำตอบด้วยวิธีแก้ปัญหา O (1) ที่มีประโยชน์มากกว่าและจดบันทึกปัญหาที่คุณระบุ ฉันแน่ใจว่า JanKanis จะขอบคุณการโหวตของคุณ
phonetagger

@phonetagger คุณควรแก้ไขคำตอบของคุณ ไม่ใช่ทุกคนที่จะอ่านคำตอบทั้งหมด
Picarus

"ไม่ใช่คำตอบเดียวที่ได้ตอบคำถามจริง" -> ปัญหาคือว่าคำถามเดิมไม่ได้เกี่ยวกับความซับซ้อนของอัลกอริทึมลองดูรุ่นของคำถาม OP ถามก่อนว่าจะผนวกองค์ประกอบในรายการได้อย่างไรหลังจากหลายเดือนต่อมาเขาเปลี่ยนคำถาม
Carlos Cinelli

41

ในคำตอบอื่น ๆ เฉพาะlistวิธีการที่ให้ผลลัพธ์ใน O (1) ต่อท้าย แต่จะส่งผลให้มีโครงสร้างของรายการที่ซ้อนกันอย่างลึกและไม่ใช่รายการเดียวที่ธรรมดา ฉันได้ใช้โครงสร้างข้อมูลด้านล่างพวกเขาสนับสนุนการผนวก O (1) (ตัดจำหน่าย) และอนุญาตให้แปลงผลลัพธ์กลับเป็นรายการธรรมดา

expandingList <- function(capacity = 10) {
    buffer <- vector('list', capacity)
    length <- 0

    methods <- list()

    methods$double.size <- function() {
        buffer <<- c(buffer, vector('list', capacity))
        capacity <<- capacity * 2
    }

    methods$add <- function(val) {
        if(length == capacity) {
            methods$double.size()
        }

        length <<- length + 1
        buffer[[length]] <<- val
    }

    methods$as.list <- function() {
        b <- buffer[0:length]
        return(b)
    }

    methods
}

และ

linkedList <- function() {
    head <- list(0)
    length <- 0

    methods <- list()

    methods$add <- function(val) {
        length <<- length + 1
        head <<- list(head, val)
    }

    methods$as.list <- function() {
        b <- vector('list', length)
        h <- head
        for(i in length:1) {
            b[[i]] <- head[[2]]
            head <- head[[1]]
        }
        return(b)
    }
    methods
}

ใช้พวกเขาดังต่อไปนี้:

> l <- expandingList()
> l$add("hello")
> l$add("world")
> l$add(101)
> l$as.list()
[[1]]
[1] "hello"

[[2]]
[1] "world"

[[3]]
[1] 101

โซลูชั่นเหล่านี้สามารถขยายเป็นวัตถุเต็มรูปแบบที่รองรับการทำงานที่เกี่ยวข้องกับรายการด้วยตนเอง แต่จะยังคงเป็นการออกกำลังกายสำหรับผู้อ่าน

ตัวแปรอื่นสำหรับรายการที่มีชื่อ:

namedExpandingList <- function(capacity = 10) {
    buffer <- vector('list', capacity)
    names <- character(capacity)
    length <- 0

    methods <- list()

    methods$double.size <- function() {
        buffer <<- c(buffer, vector('list', capacity))
        names <<- c(names, character(capacity))
        capacity <<- capacity * 2
    }

    methods$add <- function(name, val) {
        if(length == capacity) {
            methods$double.size()
        }

        length <<- length + 1
        buffer[[length]] <<- val
        names[length] <<- name
    }

    methods$as.list <- function() {
        b <- buffer[0:length]
        names(b) <- names[0:length]
        return(b)
    }

    methods
}

มาตรฐาน

การเปรียบเทียบประสิทธิภาพโดยใช้รหัสของ @ phonetagger (ซึ่งเป็นไปตามรหัสของ @Cron Arconis) ฉันได้เพิ่มbetter_env_as_containerและยังเปลี่ยนenv_as_container_เล็กน้อย ต้นฉบับenv_as_container_เสียและไม่ได้จัดเก็บตัวเลขทั้งหมด

library(microbenchmark)
lPtrAppend <- function(lstptr, lab, obj) {lstptr[[deparse(lab)]] <- obj}
### Store list inside new environment
envAppendList <- function(lstptr, obj) {lstptr$list[[length(lstptr$list)+1]] <- obj} 
env2list <- function(env, len) {
    l <- vector('list', len)
    for (i in 1:len) {
        l[[i]] <- env[[as.character(i)]]
    }
    l
}
envl2list <- function(env, len) {
    l <- vector('list', len)
    for (i in 1:len) {
        l[[i]] <- env[[paste(as.character(i), 'L', sep='')]]
    }
    l
}
runBenchmark <- function(n) {
    microbenchmark(times = 5,  
        env_with_list_ = {
            listptr <- new.env(parent=globalenv())
            listptr$list <- NULL
            for(i in 1:n) {envAppendList(listptr, i)}
            listptr$list
        },
        c_ = {
            a <- list(0)
            for(i in 1:n) {a = c(a, list(i))}
        },
        list_ = {
            a <- list(0)
            for(i in 1:n) {a <- list(a, list(i))}
        },
        by_index = {
            a <- list(0)
            for(i in 1:n) {a[length(a) + 1] <- i}
            a
        },
        append_ = { 
            a <- list(0)    
            for(i in 1:n) {a <- append(a, i)} 
            a
        },
        env_as_container_ = {
            listptr <- new.env(hash=TRUE, parent=globalenv())
            for(i in 1:n) {lPtrAppend(listptr, i, i)} 
            envl2list(listptr, n)
        },
        better_env_as_container = {
            env <- new.env(hash=TRUE, parent=globalenv())
            for(i in 1:n) env[[as.character(i)]] <- i
            env2list(env, n)
        },
        linkedList = {
            a <- linkedList()
            for(i in 1:n) { a$add(i) }
            a$as.list()
        },
        inlineLinkedList = {
            a <- list()
            for(i in 1:n) { a <- list(a, i) }
            b <- vector('list', n)
            head <- a
            for(i in n:1) {
                b[[i]] <- head[[2]]
                head <- head[[1]]
            }                
        },
        expandingList = {
            a <- expandingList()
            for(i in 1:n) { a$add(i) }
            a$as.list()
        },
        inlineExpandingList = {
            l <- vector('list', 10)
            cap <- 10
            len <- 0
            for(i in 1:n) {
                if(len == cap) {
                    l <- c(l, vector('list', cap))
                    cap <- cap*2
                }
                len <- len + 1
                l[[len]] <- i
            }
            l[1:len]
        }
    )
}

# We need to repeatedly add an element to a list. With normal list concatenation
# or element setting this would lead to a large number of memory copies and a
# quadratic runtime. To prevent that, this function implements a bare bones
# expanding array, in which list appends are (amortized) constant time.
    expandingList <- function(capacity = 10) {
        buffer <- vector('list', capacity)
        length <- 0

        methods <- list()

        methods$double.size <- function() {
            buffer <<- c(buffer, vector('list', capacity))
            capacity <<- capacity * 2
        }

        methods$add <- function(val) {
            if(length == capacity) {
                methods$double.size()
            }

            length <<- length + 1
            buffer[[length]] <<- val
        }

        methods$as.list <- function() {
            b <- buffer[0:length]
            return(b)
        }

        methods
    }

    linkedList <- function() {
        head <- list(0)
        length <- 0

        methods <- list()

        methods$add <- function(val) {
            length <<- length + 1
            head <<- list(head, val)
        }

        methods$as.list <- function() {
            b <- vector('list', length)
            h <- head
            for(i in length:1) {
                b[[i]] <- head[[2]]
                head <- head[[1]]
            }
            return(b)
        }

        methods
    }

# We need to repeatedly add an element to a list. With normal list concatenation
# or element setting this would lead to a large number of memory copies and a
# quadratic runtime. To prevent that, this function implements a bare bones
# expanding array, in which list appends are (amortized) constant time.
    namedExpandingList <- function(capacity = 10) {
        buffer <- vector('list', capacity)
        names <- character(capacity)
        length <- 0

        methods <- list()

        methods$double.size <- function() {
            buffer <<- c(buffer, vector('list', capacity))
            names <<- c(names, character(capacity))
            capacity <<- capacity * 2
        }

        methods$add <- function(name, val) {
            if(length == capacity) {
                methods$double.size()
            }

            length <<- length + 1
            buffer[[length]] <<- val
            names[length] <<- name
        }

        methods$as.list <- function() {
            b <- buffer[0:length]
            names(b) <- names[0:length]
            return(b)
        }

        methods
    }

ผลลัพธ์:

> runBenchmark(1000)
Unit: microseconds
                    expr       min        lq      mean    median        uq       max neval
          env_with_list_  3128.291  3161.675  4466.726  3361.837  3362.885  9318.943     5
                      c_  3308.130  3465.830  6687.985  8578.913  8627.802  9459.252     5
                   list_   329.508   343.615   389.724   370.504   449.494   455.499     5
                by_index  3076.679  3256.588  5480.571  3395.919  8209.738  9463.931     5
                 append_  4292.321  4562.184  7911.882 10156.957 10202.773 10345.177     5
       env_as_container_ 24471.511 24795.849 25541.103 25486.362 26440.591 26511.200     5
 better_env_as_container  7671.338  7986.597  8118.163  8153.726  8335.659  8443.493     5
              linkedList  1700.754  1755.439  1829.442  1804.746  1898.752  1987.518     5
        inlineLinkedList  1109.764  1115.352  1163.751  1115.631  1206.843  1271.166     5
           expandingList  1422.440  1439.970  1486.288  1519.728  1524.268  1525.036     5
     inlineExpandingList   942.916   973.366  1002.461  1012.197  1017.784  1066.044     5
> runBenchmark(10000)
Unit: milliseconds
                    expr        min         lq       mean     median         uq        max neval
          env_with_list_ 357.760419 360.277117 433.810432 411.144799 479.090688 560.779139     5
                      c_ 685.477809 734.055635 761.689936 745.957553 778.330873 864.627811     5
                   list_   3.257356   3.454166   3.505653   3.524216   3.551454   3.741071     5
                by_index 445.977967 454.321797 515.453906 483.313516 560.374763 633.281485     5
                 append_ 610.777866 629.547539 681.145751 640.936898 760.570326 763.896124     5
       env_as_container_ 281.025606 290.028380 303.885130 308.594676 314.972570 324.804419     5
 better_env_as_container  83.944855  86.927458  90.098644  91.335853  92.459026  95.826030     5
              linkedList  19.612576  24.032285  24.229808  25.461429  25.819151  26.223597     5
        inlineLinkedList  11.126970  11.768524  12.216284  12.063529  12.392199  13.730200     5
           expandingList  14.735483  15.854536  15.764204  16.073485  16.075789  16.081726     5
     inlineExpandingList  10.618393  11.179351  13.275107  12.391780  14.747914  17.438096     5
> runBenchmark(20000)
Unit: milliseconds
                    expr         min          lq       mean      median          uq         max neval
          env_with_list_ 1723.899913 1915.003237 1921.23955 1938.734718 1951.649113 2076.910767     5
                      c_ 2759.769353 2768.992334 2810.40023 2820.129738 2832.350269 2870.759474     5
                   list_    6.112919    6.399964    6.63974    6.453252    6.910916    7.321647     5
                by_index 2163.585192 2194.892470 2292.61011 2209.889015 2436.620081 2458.063801     5
                 append_ 2832.504964 2872.559609 2983.17666 2992.634568 3004.625953 3213.558197     5
       env_as_container_  573.386166  588.448990  602.48829  597.645221  610.048314  642.912752     5
 better_env_as_container  154.180531  175.254307  180.26689  177.027204  188.642219  206.230191     5
              linkedList   38.401105   47.514506   46.61419   47.525192   48.677209   50.952958     5
        inlineLinkedList   25.172429   26.326681   32.33312   34.403442   34.469930   41.293126     5
           expandingList   30.776072   30.970438   34.45491   31.752790   38.062728   40.712542     5
     inlineExpandingList   21.309278   22.709159   24.64656   24.290694   25.764816   29.158849     5

ฉันได้เพิ่มlinkedListและexpandingListทั้งสองรุ่นอินไลน์ inlinedLinkedListเป็นพื้นสำเนาของlist_แต่มันยังแปลงกลับโครงสร้างที่ซ้อนกันเป็นรายการธรรมดา ยิ่งไปกว่านั้นความแตกต่างระหว่างเวอร์ชันที่ inline และ non-inlined นั้นเกิดจากโอเวอร์เฮดของการเรียกฟังก์ชั่น

ตัวแปรทั้งหมดexpandingListและlinkedListแสดง O (1) ผนวกประสิทธิภาพการทำงานโดยมีการกำหนดเวลาการวัดเชิงเส้นตรงตามจำนวนรายการที่เพิ่ม linkedListช้ากว่าexpandingListและฟังก์ชั่นค่าใช้จ่ายในการโทรก็สามารถมองเห็นได้เช่นกัน ดังนั้นถ้าคุณต้องการจริงๆทุกความเร็วที่คุณจะได้รับ (และต้องการที่จะติดรหัส R) ซึ่งใช้รุ่น inlined expandingListของ

ฉันยังได้ดูการใช้งาน C ของ R และวิธีการทั้งสองควรเป็น O (1) ผนวกทุกขนาดจนถึงหน่วยความจำไม่เพียงพอ

ฉันได้เปลี่ยนไปenv_as_container_แล้วเวอร์ชั่นดั้งเดิมจะจัดเก็บทุกรายการภายใต้ดัชนี "i" เขียนทับรายการที่ต่อท้ายก่อนหน้านี้ better_env_as_containerฉันได้เพิ่มจะคล้ายกับenv_as_container_แต่ไม่มีdeparseสิ่ง ทั้งสองแสดงประสิทธิภาพ O (1) แต่มีค่าใช้จ่ายที่ค่อนข้างใหญ่กว่ารายการที่เชื่อมโยง / ขยาย

หน่วยความจำเหนือศีรษะ

ในการนำ CR ไปใช้จะมีค่าใช้จ่าย 4 คำและ 2 int ต่อวัตถุที่ปันส่วน linkedListวิธีนี้จะจัดสรรรายการหนึ่งรายการที่มีความยาวสองรายการต่อท้ายรวม (4 * 8 + 4 + 4 + 2 * 8 =) 56 ไบต์ต่อรายการต่อท้ายบนคอมพิวเตอร์ 64 บิต (ไม่รวมค่าใช้จ่ายในการจัดสรรหน่วยความจำดังนั้นอาจใกล้ถึง 64 bytes) expandingListวิธีการใช้หนึ่งคำต่อท้ายรายการรวมทั้งสำเนาเมื่อสองเท่าของความยาวเวกเตอร์เพื่อให้การใช้งานหน่วยความจำทั้งหมดถึง 16 ไบต์ต่อรายการ เนื่องจากหน่วยความจำทั้งหมดในหนึ่งหรือสองวัตถุค่าใช้จ่ายต่อวัตถุไม่สำคัญ ฉันไม่ได้มองลึกลงไปในenvการใช้งานหน่วยความจำ linkedListแต่ฉันคิดว่ามันจะได้ใกล้ชิดกับ


อะไรคือจุดรักษาตัวเลือกรายการหากไม่สามารถแก้ปัญหาที่เราพยายามแก้ไขได้
Picarus

1
@Picarus ฉันไม่แน่ใจว่าคุณหมายถึงอะไร ทำไมฉันถึงเก็บไว้ในเกณฑ์มาตรฐาน? เป็นการเปรียบเทียบกับตัวเลือกอื่น ๆ list_ตัวเลือกที่เร็วขึ้นและอาจจะมีประโยชน์ถ้าคุณไม่จำเป็นต้องแปลงไปยังรายการปกติเช่นถ้าคุณใช้ผลตามที่กอง
JanKanis

@Gabor Csardi โพสต์วิธีที่เร็วกว่าในการแปลงสภาพแวดล้อมกลับสู่รายการด้วยคำถามที่แตกต่างกันที่ stackoverflow.com/a/29482211/264177 ฉันเปรียบเทียบว่าด้วยระบบของฉัน มันเร็วกว่า better_env_as_container ประมาณสองเท่า แต่ก็ยังช้ากว่า linkedList และ expandList
JanKanis

ซ้อนกันอย่างลึกซึ้ง (n = 99999) รายการดูเหมือนจัดการได้และพอประมาณสำหรับการใช้งานบางอย่างที่ทุกคนต้องการที่จะมาตรฐานNestor ? (ฉันยังคงเป็น noob ที่environmentสิ่งที่ฉันใช้สำหรับ nestoR.) คอขวดของฉันเกือบตลอดเวลาที่มนุษย์ใช้ในการเขียนโค้ดและทำการวิเคราะห์ข้อมูล แต่ฉันขอบคุณมาตรฐานที่ฉันพบในโพสต์นี้ สำหรับโอเวอร์เฮดของหน่วยความจำฉันจะไม่สนใจเรื่อง kB ต่อโหนดสำหรับแอปพลิเคชันของฉัน ฉันถืออาร์เรย์ขนาดใหญ่ ฯลฯ
Ana Nimbus

17

ในเสียงกระเพื่อมเราทำอย่างนี้:

> l <- c(1)
> l <- c(2, l)
> l <- c(3, l)
> l <- rev(l)
> l
[1] 1 2 3

แม้ว่ามันจะเป็น 'ข้อเสีย' ไม่ใช่แค่ 'c' หากคุณต้องการเริ่มต้นด้วยรายการ empy ให้ใช้ l <- NULL


3
ยอดเยี่ยม โซลูชันอื่น ๆ ทั้งหมดจะส่งคืนรายการแปลก ๆ บางรายการ
metakermit

4
ใน Lisp การเพิ่มไปยังรายการเป็นการดำเนินการ O (1) ในขณะที่ผนวกการทำงานใน O (n), @flies ความต้องการในการพลิกกลับมีมากกว่าเมื่อได้รับประสิทธิภาพ นี่ไม่ใช่กรณีใน R ไม่ใช่แม้แต่ใน pairlist ซึ่งโดยทั่วไปจะคล้ายกับ List มากที่สุด
Palec

@Palec "นี่ไม่ใช่กรณีใน R" - ฉันไม่แน่ใจว่าคุณกำลังอ้างถึง "this" นี้ คุณกำลังบอกว่าการต่อท้ายไม่ใช่ O (1) หรือไม่ใช่ O (n)?
บิน

1
ฉันกำลังบอกว่าถ้าคุณกำลังเขียนโปรแกรมใน Lisp วิธีการของคุณจะไม่มีประสิทธิภาพ @flies คำพูดนั้นมีไว้เพื่ออธิบายว่าทำไมคำตอบนั้นถูกเขียนขึ้นอย่างที่มันเป็น ใน R ทั้งสองวิธีอยู่ที่ AFAIK อย่างชาญฉลาด แต่ตอนนี้ฉันไม่แน่ใจเกี่ยวกับความซับซ้อนที่ถูกตัดจำหน่าย ยังไม่ได้สัมผัส R ตั้งแต่เวลาที่ความคิดเห็นก่อนหน้าของฉันถูกเขียน
Palec

3
ใน R วิธีนี้จะเป็น O (n) c()สำเนาฟังก์ชั่นการขัดแย้งของมันเข้าไปในเวกเตอร์ใหม่ / รายการและผลตอบแทนที่
JanKanis

6

คุณต้องการอะไรแบบนี้อาจจะ?

> push <- function(l, x) {
   lst <- get(l, parent.frame())
   lst[length(lst)+1] <- x
   assign(l, lst, envir=parent.frame())
 }
> a <- list(1,2)
> push('a', 6)
> a
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 6

มันไม่ใช่ฟังก์ชั่นที่สุภาพมาก (การกำหนดให้parent.frame()เป็นเรื่องหยาบคาย) แต่ IIUYC เป็นสิ่งที่คุณต้องการ


6

ฉันได้เปรียบเทียบวิธีการเล็กน้อยที่กล่าวถึงที่นี่

n = 1e+4
library(microbenchmark)
### Using environment as a container
lPtrAppend <- function(lstptr, lab, obj) {lstptr[[deparse(substitute(lab))]] <- obj}
### Store list inside new environment
envAppendList <- function(lstptr, obj) {lstptr$list[[length(lstptr$list)+1]] <- obj} 

microbenchmark(times = 5,  
        env_with_list_ = {
            listptr <- new.env(parent=globalenv())
            listptr$list <- NULL
            for(i in 1:n) {envAppendList(listptr, i)}
            listptr$list
        },
        c_ = {
            a <- list(0)
            for(i in 1:n) {a = c(a, list(i))}
        },
        list_ = {
            a <- list(0)
            for(i in 1:n) {a <- list(a, list(i))}
        },
        by_index = {
            a <- list(0)
            for(i in 1:n) {a[length(a) + 1] <- i}
            a
        },
        append_ = { 
            a <- list(0)    
            for(i in 1:n) {a <- append(a, i)} 
            a
        },
        env_as_container_ = {
            listptr <- new.env(parent=globalenv())
            for(i in 1:n) {lPtrAppend(listptr, i, i)} 
            listptr
        }   
)

ผล:

Unit: milliseconds
              expr       min        lq       mean    median        uq       max neval cld
    env_with_list_  188.9023  198.7560  224.57632  223.2520  229.3854  282.5859     5  a 
                c_ 1275.3424 1869.1064 2022.20984 2191.7745 2283.1199 2491.7060     5   b
             list_   17.4916   18.1142   22.56752   19.8546   20.8191   36.5581     5  a 
          by_index  445.2970  479.9670  540.20398  576.9037  591.2366  607.6156     5  a 
           append_ 1140.8975 1316.3031 1794.10472 1620.1212 1855.3602 3037.8416     5   b
 env_as_container_  355.9655  360.1738  399.69186  376.8588  391.7945  513.6667     5  a 

นี่คือข้อมูลที่ยอดเยี่ยม: จะไม่เคยเดาเลยว่าสิ่งlist = listเหล่านั้นไม่เพียง แต่เป็นผู้ชนะ แต่ยังมีออเดอร์หรือขนาด 1 ถึง 2!
javadba

5

หากคุณผ่านรายการตัวแปรเป็นสตริงที่ยกมาคุณสามารถเข้าถึงได้จากภายในฟังก์ชั่นเช่น:

push <- function(l, x) {
  assign(l, append(eval(as.name(l)), x), envir=parent.frame())
}

ดังนั้น:

> a <- list(1,2)
> a
[[1]]
[1] 1

[[2]]
[1] 2

> push("a", 3)
> a
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

> 

หรือสำหรับเครดิตพิเศษ:

> v <- vector()
> push("v", 1)
> v
[1] 1
> push("v", 2)
> v
[1] 1 2
> 

1
นี่เป็นพฤติกรรมที่ฉันต้องการ แต่ก็ยังคงเรียกใช้ผนวกภายในทำให้มีประสิทธิภาพ O (n ^ 2)
Nick

4

ไม่แน่ใจว่าทำไมคุณไม่คิดว่าวิธีแรกของคุณจะไม่ทำงาน คุณมีข้อผิดพลาดในฟังก์ชั่น lappend: length (รายการ) ควรเป็น length (lst) ใช้งานได้ดีและส่งคืนรายการด้วย obj ต่อท้าย


3
คุณพูดถูก มีข้อผิดพลาดในรหัสและฉันได้แก้ไขแล้ว ฉันได้ทดสอบสิ่งlappend()ที่ฉันให้มาแล้วและดูเหมือนว่าจะทำงานได้ดีเท่ากับ c () และผนวก () ซึ่งทั้งหมดนั้นแสดงพฤติกรรม O (n ^ 2)
นิค


2

ผมคิดว่าสิ่งที่คุณต้องการจะทำคือจริงผ่านโดยการอ้างอิง (ชี้) เพื่อ function-- สร้างสภาพแวดล้อมใหม่ (ซึ่งจะถูกส่งผ่านโดยอ้างอิงถึงฟังก์ชั่น) ที่มีรายชื่อที่เพิ่มให้กับมัน

listptr=new.env(parent=globalenv())
listptr$list=mylist

#Then the function is modified as:
lPtrAppend <- function(lstptr, obj) {
    lstptr$list[[length(lstptr$list)+1]] <- obj
}

ตอนนี้คุณกำลังแก้ไขรายการที่มีอยู่เท่านั้น (ไม่ได้สร้างรายการใหม่)


1
ดูเหมือนว่าจะมีความซับซ้อนของเวลากำลังสองอีกครั้ง ปัญหาคือชัดว่ารายการ / เวกเตอร์ปรับขนาดไม่ได้ดำเนินการตามวิธีที่มักจะใช้ในภาษาส่วนใหญ่
eold

ใช่ - ดูเหมือนว่าการผนวกท้ายจะช้ามาก - อาจเป็นรายการ b / c ที่เรียกซ้ำและ R นั้นดีที่สุดในการดำเนินการของเวกเตอร์แทนที่จะเป็นการดำเนินการประเภทวนรอบ มันดีกว่ามากที่ทำได้:
DavidM

1
system.time (สำหรับ (i ใน c (1: 10,000) mylist [i] = i) (ไม่กี่วินาที) หรือดีกว่ายังทำได้ทั้งหมดในการดำเนินการครั้งเดียว: system.time (รายการ mylist = (1: 100000)) (น้อยกว่าหนึ่งวินาที) จากนั้นแก้ไขรายการที่จัดสรรล่วงหน้าด้วย for loop จะเร็วขึ้นด้วย
DavidM

2

นี่เป็นวิธีที่ง่ายในการเพิ่มรายการไปยังรายการ R:

# create an empty list:
small_list = list()

# now put some objects in it:
small_list$k1 = "v1"
small_list$k2 = "v2"
small_list$k3 = 1:10

# retrieve them the same way:
small_list$k1
# returns "v1"

# "index" notation works as well:
small_list["k2"]

หรือโดยทางโปรแกรม:

kx = paste(LETTERS[1:5], 1:5, sep="")
vx = runif(5)
lx = list()
cn = 1

for (itm in kx) { lx[itm] = vx[cn]; cn = cn + 1 }

print(length(lx))
# returns 5

นี่ไม่ได้เป็นการต่อท้ายจริงๆ ถ้าฉันมีวัตถุ 100 รายการและฉันต้องการเพิ่มรายการเหล่านั้นลงในรายการโดยทางโปรแกรม R มีappend()ฟังก์ชั่น แต่มันเป็นฟังก์ชั่นที่ต่อกันกันและใช้ได้กับเวกเตอร์เท่านั้น
Nick

append()ทำงานกับเวกเตอร์และรายการและเป็นภาคผนวกจริง (ซึ่งโดยทั่วไปเหมือนกับ concatenate ดังนั้นฉันไม่เห็นปัญหาของคุณ)
hadley

8
ฟังก์ชั่นผนวกควรกลายพันธุ์วัตถุที่มีอยู่ไม่ได้สร้างใหม่ การผนวกที่แท้จริงจะไม่มีลักษณะการทำงานของ O (N ^ 2)
Nick

2

ในความเป็นจริงมีความแปลกประหลาดกับc()ฟังก์ชั่น ถ้าคุณทำ:

x <- list()
x <- c(x,2)
x = c(x,"foo")

คุณจะได้รับตามที่คาดไว้:

[[1]]
[1]

[[2]]
[1] "foo"

แต่ถ้าคุณเพิ่มเมทริกซ์ด้วยx <- c(x, matrix(5,2,2)ลิสต์ของคุณจะมีค่าอีก 4 องค์ประกอบ5! คุณควรที่จะทำ:

x <- c(x, list(matrix(5,2,2))

มันใช้งานได้กับวัตถุอื่นและคุณจะได้รับตามที่คาดไว้:

[[1]]
[1]

[[2]]
[1] "foo"

[[3]]
     [,1] [,2]
[1,]    5    5
[2,]    5    5

ในที่สุดฟังก์ชั่นของคุณจะกลายเป็น:

push <- function(l, ...) c(l, list(...))

และใช้ได้กับวัตถุทุกประเภท คุณสามารถฉลาดขึ้นและทำ:

push_back <- function(l, ...) c(l, list(...))
push_front <- function(l, ...) c(list(...), l)

1

นอกจากนี้ยังมีlist.appendจากrlist( ลิงก์ไปยังเอกสารประกอบ )

require(rlist)
LL <- list(a="Tom", b="Dick")
list.append(LL,d="Pam",f=c("Joe","Ann"))

มันง่ายมากและมีประสิทธิภาพ


1
ดูเหมือน R กับฉัน ... Python?
JD Long

1
ฉันทำการแก้ไขและทดลองใช้: มันช้ามาก ดีกว่าใช้c()หรือlist-method ทั้งสองวิธีเร็วขึ้น
5

มองหารหัสสำหรับมันเป็นหลักรอบเสื้อคลุมrlist::list.append() base::c()
nbenn

1

เพื่อการตรวจสอบฉันใช้รหัสมาตรฐานที่ @Cron มอบให้ มีความแตกต่างที่สำคัญอย่างหนึ่ง (นอกเหนือจากการทำงานที่เร็วขึ้นบนโปรเซสเซอร์ i7 รุ่นใหม่กว่า): by_indexประสิทธิภาพในขณะนี้เกือบจะเป็นlist_:

Unit: milliseconds
              expr        min         lq       mean     median         uq
    env_with_list_ 167.882406 175.969269 185.966143 181.817187 185.933887
                c_ 485.524870 501.049836 516.781689 518.637468 537.355953
             list_   6.155772   6.258487   6.544207   6.269045   6.290925
          by_index   9.290577   9.630283   9.881103   9.672359  10.219533
           append_ 505.046634 543.319857 542.112303 551.001787 553.030110
 env_as_container_ 153.297375 154.880337 156.198009 156.068736 156.800135

สำหรับการอ้างอิงที่นี่คือรหัสมาตรฐานคัดลอกคำต่อคำจาก @ Cron ของคำตอบ (ในกรณีที่เขาเปลี่ยนเนื้อหาในภายหลัง):

n = 1e+4
library(microbenchmark)
### Using environment as a container
lPtrAppend <- function(lstptr, lab, obj) {lstptr[[deparse(substitute(lab))]] <- obj}
### Store list inside new environment
envAppendList <- function(lstptr, obj) {lstptr$list[[length(lstptr$list)+1]] <- obj}

microbenchmark(times = 5,
        env_with_list_ = {
            listptr <- new.env(parent=globalenv())
            listptr$list <- NULL
            for(i in 1:n) {envAppendList(listptr, i)}
            listptr$list
        },
        c_ = {
            a <- list(0)
            for(i in 1:n) {a = c(a, list(i))}
        },
        list_ = {
            a <- list(0)
            for(i in 1:n) {a <- list(a, list(i))}
        },
        by_index = {
            a <- list(0)
            for(i in 1:n) {a[length(a) + 1] <- i}
            a
        },
        append_ = {
            a <- list(0)
            for(i in 1:n) {a <- append(a, i)}
            a
        },
        env_as_container_ = {
            listptr <- new.env(parent=globalenv())
            for(i in 1:n) {lPtrAppend(listptr, i, i)}
            listptr
        }
)

0
> LL<-list(1:4)

> LL

[[1]]
[1] 1 2 3 4

> LL<-list(c(unlist(LL),5:9))

> LL

[[1]]
 [1] 1 2 3 4 5 6 7 8 9

2
ฉันไม่คิดว่านี่เป็นประเภทของการผนวก OP ที่กำลังมองหา
joran

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

0

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

a_list<-list()
for(i in 1:3){
  a_list<-list(unlist(list(unlist(a_list,recursive = FALSE),list(rnorm(2))),recursive = FALSE))
}
a_list

[[1]]
[[1]][[1]]
[1] -0.8098202  1.1035517

[[1]][[2]]
[1] 0.6804520 0.4664394

[[1]][[3]]
[1] 0.15592354 0.07424637

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

-1

mylist<-list(1,2,3) mylist<-c(mylist,list(5))

ดังนั้นเราสามารถผนวกองค์ประกอบ / วัตถุได้อย่างง่ายดายโดยใช้โค้ดด้านบน

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