क्या पूर्णांक की एक सीमा पर पुनरावृति करने का एक तरीका है?


174

गो की रेंज मैप्स और स्लाइस पर पुनरावृति कर सकती है, लेकिन मैं सोच रहा था कि क्या संख्याओं की श्रेणी में पुनरावृति करने का कोई तरीका है, इस पर कुछ:

for i := range [1..10] {
    fmt.Println(i)
}

या गो में पूर्णांकों की श्रेणी का प्रतिनिधित्व करने का एक तरीका है जैसे कि रूबी वर्ग श्रेणी के साथ कैसे करता है ?

जवाबों:


224

आप कर सकते हैं, और बस लूप के लिए लिखना चाहिए। सरल, स्पष्ट कोड है रास्ता।

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

268
मुझे नहीं लगता कि ज्यादातर लोग इस तीन-अभिव्यक्ति संस्करण को @Vishnu द्वारा लिखे गए से अधिक सरल कहेंगे। सी या जावा इंडोक्रिएशन के वर्षों के बाद ही शायद ;-)
थॉमस अहले

12
IMO बिंदु यह है कि आपके पास हमेशा लूप के लिए यह तीन-अभिव्यक्ति संस्करण होने वाले हैं (यानी आप इसके साथ बहुत कुछ कर सकते हैं, ओपी से वाक्यविन्यास केवल एक नंबर सीमा के उस अधिक प्रतिबंधित मामले के लिए अच्छा है, इसलिए किसी भी भाषा में आप इस विस्तारित संस्करण को चाहते हैं) और यह पर्याप्त रूप से एक ही कार्य को पूरा करता है, और किसी भी तरह से उल्लेखनीय रूप से भिन्न नहीं है, इसलिए दूसरे सिंटैक्स को सीखना / याद रखना है। यदि आप एक बड़े और जटिल प्रोजेक्ट पर कोडिंग कर रहे हैं, तो आपके पास पहले से ही चिंता करने के लिए पर्याप्त है बिना लूप के रूप में कुछ के लिए विभिन्न सिंटैक्स के बारे में संकलक से लड़ने के लिए।
ब्रैड पीबॉडी

3
@ThomasAhle विशेष रूप से C ++ पर विचार करते हुए आधिकारिक तौर पर बढ़ावा देने वाले खाका पुस्तकालय से प्रेरित for_each (x, y) के लिए संकेतन जोड़ रहा है
चमकदार '

5
@BradPeabody यह वास्तव में प्राथमिकता का विषय है। पायथन में 3-अभिव्यक्ति लूप नहीं है और ठीक काम करता है। कई लोग प्रत्येक वाक्य-विन्यास को बहुत कम त्रुटि-प्रधान मानते हैं और इसके बारे में आंतरिक रूप से अक्षम कुछ भी नहीं है।
विनगरिया

3
@necromancer यहाँ रोब पाईक की एक पोस्ट है जो मेरे उत्तर के समान ही है। groups.google.com/d/msg/golang-nuts/7J8FY07dkW0/goWaNVOkQU0J । यह हो सकता है कि गो समुदाय असहमत हो, लेकिन जब यह भाषा के लेखकों में से एक से सहमत होता है, तो यह वास्तव में एक उत्तर का बुरा नहीं हो सकता है।
पॉल हैंकिन

43

यहां अब तक सुझाए गए दो तरीकों की तुलना करने का एक कार्यक्रम है

import (
    "fmt"

    "github.com/bradfitz/iter"
)

func p(i int) {
    fmt.Println(i)
}

func plain() {
    for i := 0; i < 10; i++ {
        p(i)
    }
}

func with_iter() {
    for i := range iter.N(10) {
        p(i)
    }
}

func main() {
    plain()
    with_iter()
}

इस प्रकार संकलन करें जिससे डिस्सैड उत्पन्न किया जा सके

go build -gcflags -S iter.go

यहाँ सादा है (मैंने सूची से गैर निर्देश हटा दिए हैं)

सेट अप

0035 (/home/ncw/Go/iter.go:14) MOVQ    $0,AX
0036 (/home/ncw/Go/iter.go:14) JMP     ,38

पाश

0037 (/home/ncw/Go/iter.go:14) INCQ    ,AX
0038 (/home/ncw/Go/iter.go:14) CMPQ    AX,$10
0039 (/home/ncw/Go/iter.go:14) JGE     $0,45
0040 (/home/ncw/Go/iter.go:15) MOVQ    AX,i+-8(SP)
0041 (/home/ncw/Go/iter.go:15) MOVQ    AX,(SP)
0042 (/home/ncw/Go/iter.go:15) CALL    ,p+0(SB)
0043 (/home/ncw/Go/iter.go:15) MOVQ    i+-8(SP),AX
0044 (/home/ncw/Go/iter.go:14) JMP     ,37
0045 (/home/ncw/Go/iter.go:17) RET     ,

और यहाँ with_iter है

सेट अप

0052 (/home/ncw/Go/iter.go:20) MOVQ    $10,AX
0053 (/home/ncw/Go/iter.go:20) MOVQ    $0,~r0+-24(SP)
0054 (/home/ncw/Go/iter.go:20) MOVQ    $0,~r0+-16(SP)
0055 (/home/ncw/Go/iter.go:20) MOVQ    $0,~r0+-8(SP)
0056 (/home/ncw/Go/iter.go:20) MOVQ    $type.[]struct {}+0(SB),(SP)
0057 (/home/ncw/Go/iter.go:20) MOVQ    AX,8(SP)
0058 (/home/ncw/Go/iter.go:20) MOVQ    AX,16(SP)
0059 (/home/ncw/Go/iter.go:20) PCDATA  $0,$48
0060 (/home/ncw/Go/iter.go:20) CALL    ,runtime.makeslice+0(SB)
0061 (/home/ncw/Go/iter.go:20) PCDATA  $0,$-1
0062 (/home/ncw/Go/iter.go:20) MOVQ    24(SP),DX
0063 (/home/ncw/Go/iter.go:20) MOVQ    32(SP),CX
0064 (/home/ncw/Go/iter.go:20) MOVQ    40(SP),AX
0065 (/home/ncw/Go/iter.go:20) MOVQ    DX,~r0+-24(SP)
0066 (/home/ncw/Go/iter.go:20) MOVQ    CX,~r0+-16(SP)
0067 (/home/ncw/Go/iter.go:20) MOVQ    AX,~r0+-8(SP)
0068 (/home/ncw/Go/iter.go:20) MOVQ    $0,AX
0069 (/home/ncw/Go/iter.go:20) LEAQ    ~r0+-24(SP),BX
0070 (/home/ncw/Go/iter.go:20) MOVQ    8(BX),BP
0071 (/home/ncw/Go/iter.go:20) MOVQ    BP,autotmp_0006+-32(SP)
0072 (/home/ncw/Go/iter.go:20) JMP     ,74

पाश

0073 (/home/ncw/Go/iter.go:20) INCQ    ,AX
0074 (/home/ncw/Go/iter.go:20) MOVQ    autotmp_0006+-32(SP),BP
0075 (/home/ncw/Go/iter.go:20) CMPQ    AX,BP
0076 (/home/ncw/Go/iter.go:20) JGE     $0,82
0077 (/home/ncw/Go/iter.go:20) MOVQ    AX,autotmp_0005+-40(SP)
0078 (/home/ncw/Go/iter.go:21) MOVQ    AX,(SP)
0079 (/home/ncw/Go/iter.go:21) CALL    ,p+0(SB)
0080 (/home/ncw/Go/iter.go:21) MOVQ    autotmp_0005+-40(SP),AX
0081 (/home/ncw/Go/iter.go:20) JMP     ,73
0082 (/home/ncw/Go/iter.go:23) RET     ,

तो आप देख सकते हैं कि इटेर सॉल्यूशन सेटअप चरण में पूरी तरह से इनबिल्ड होने के बावजूद काफी महंगा है। लूप चरण में लूप में एक अतिरिक्त निर्देश है, लेकिन यह बहुत बुरा नहीं है।

मैं लूप के लिए सरल का उपयोग करता हूं।


8
मैं "यह नहीं देख सकता कि पुनरावृति समाधान अधिक महंगा है।" मतगणना के अपने तरीके को छद्म कोडांतरक निर्देश त्रुटिपूर्ण है। एक बेंचमार्क चलाएं।
पेट्रो

11
एक समाधान कहता है runtime.makesliceऔर दूसरा नहीं - मुझे यह जानने के लिए बेंचमार्क की आवश्यकता नहीं है कि यह बहुत धीमा होने वाला है!
निक क्रेग-वुड

6
runtime.makesliceयदि आप शून्य आकार आवंटन के लिए कहते हैं तो हां किसी भी स्मृति को आवंटित करने के लिए पर्याप्त चतुर नहीं है। हालाँकि उपरोक्त अभी भी इसे कहते हैं, और आपके बेंचमार्क के अनुसार मेरी मशीन पर 10nS से अधिक समय लगता है।
निक क्रेग-वुड

4
लोगों को यह याद दिलाता है कि प्रदर्शन कारणों से C ++ का C + उपयोग करने का सुझाव है
नेक्रोमांसर

5
नैनो-सेकेंड सीपीयू ऑपरेशंस के रनटाइम प्रदर्शन का बहस करते हुए, जबकि गोलैंड में आम, मुझे मूर्खतापूर्ण लगता है। मुझे लगता है कि पठनीयता के बाद, बहुत दूर का अंतिम विचार होगा। यहां तक ​​कि अगर सीपीयू प्रदर्शन प्रासंगिक थे, तो लूप के लिए सामग्री केवल लूप द्वारा किए गए मतभेदों को लगभग हमेशा स्वाइप करेगी।
जोनाथन हार्टले

34

यह मार्क मिशिन द्वारा स्लाइस का उपयोग करने का सुझाव दिया गया था, लेकिन इसके साथ सरणी बनाने का कोई कारण नहीं है makeऔर इसके forलौटाए गए स्लाइस में उपयोग करने का कोई कारण नहीं है, जब शाब्दिक के माध्यम से बनाई गई सरणी का उपयोग किया जा सकता है और यह छोटा है

for i := range [5]int{} {
        fmt.Println(i)
}

8
यदि आप वैरिएबल का उपयोग नहीं करने जा रहे हैं, तो आप बायीं ओर से भी for range [5]int{} {
हट

6
दोष यह है कि 5यहाँ एक शाब्दिक है और रन-टाइम पर निर्धारित नहीं किया जा सकता है।
स्टीव पॉवेल

क्या यह लूप के लिए सामान्य तीन अभिव्यक्तियों के लिए तेज़ या तुलनीय है?
अमित त्रिपाठी

@AmitTripathi हाँ, यह तुलनीय है, निष्पादन का समय अरबों पुनरावृत्तियों के लिए लगभग समान है।
डेनियल ग्रैनकिन

18

iter एक बहुत छोटा पैकेज है जो सिर्फ पूर्णांकों पर पुनरावृति करने के लिए एक अलग-अलग तरीका प्रदान करता है।

for i := range iter.N(4) {
    fmt.Println(i)
}

रॉब पाइक (गो के एक लेखक) ने इसकी आलोचना की है :

ऐसा लगता है कि लगभग हर बार किसी व्यक्ति को लूप के लिए कुछ करने से बचने का एक तरीका आता है, क्योंकि यह बहुत लंबा या बोझिल लगता है, परिणाम लगभग हमेशा उस चीज़ की तुलना में अधिक कीस्ट्रोक्स होता है जो माना जाता है कि कम है। [...] यह "सुधार" लाने वाले सभी पागल उपरि को एक तरफ छोड़ रहा है।


16
पाइक की समालोचना इस मायने में सरल है कि यह केवल रेडक्रेलिंग रेंज के मानसिक उपरि के बजाय कीस्ट्रोक्स को संबोधित करता है। अधिकांश आधुनिक संपादकों के साथ, iterसंस्करण वास्तव में कम कीस्ट्रोक्स का उपयोग करता है क्योंकि rangeऔर iterस्वत: पूर्ण होगा।
क्रिस रेडफोर्ड

1
@ lang2, forलूप्स यूनिक्स के प्रथम श्रेणी के नागरिक नहीं हैं , जैसे वे अंदर जाते हैं। इसके अलावा, इसके विपरीत for, seqमानक आउटपुट के लिए धाराएँ क्रमबद्ध होती हैं। उपभोक्ता पर निर्भर है या नहीं। हालांकि for i in $(seq 1 10); do ... done शेल में आम है, यह लूप के लिए केवल एक ही तरीका है, जो खुद के आउटपुट का उपभोग करने का केवल एक ही तरीका है seq, हालांकि यह बहुत आम है।
डैनियल फैरेल

2
इसके अलावा, पाइक बस इस तथ्य पर विचार नहीं करता है कि एक संकलन (भाषा के चश्मे में इस उपयोग के मामले के लिए एक सीमा सिंटैक्स शामिल है) को i in range(10)ठीक उसी तरह से बनाने के लिए बनाया जा सकता है i := 0; i < 10; i++
रूवेन बी।

8

यहाँ पैकेज के प्रयोग से forForClause और Go स्टेटमेंट के साथ गो स्टेटमेंट की तुलना करने के लिए एक बेंचमार्क है ।rangeiter

iter_test.go

package main

import (
    "testing"

    "github.com/bradfitz/iter"
)

const loops = 1e6

func BenchmarkForClause(b *testing.B) {
    b.ReportAllocs()
    j := 0
    for i := 0; i < b.N; i++ {
        for j = 0; j < loops; j++ {
            j = j
        }
    }
    _ = j
}

func BenchmarkRangeIter(b *testing.B) {
    b.ReportAllocs()
    j := 0
    for i := 0; i < b.N; i++ {
        for j = range iter.N(loops) {
            j = j
        }
    }
    _ = j
}

// It does not cause any allocations.
func N(n int) []struct{} {
    return make([]struct{}, n)
}

func BenchmarkIterAllocs(b *testing.B) {
    b.ReportAllocs()
    var n []struct{}
    for i := 0; i < b.N; i++ {
        n = iter.N(loops)
    }
    _ = n
}

आउटपुट:

$ go test -bench=. -run=.
testing: warning: no tests to run
PASS
BenchmarkForClause      2000       1260356 ns/op           0 B/op          0 allocs/op
BenchmarkRangeIter      2000       1257312 ns/op           0 B/op          0 allocs/op
BenchmarkIterAllocs 20000000            82.2 ns/op         0 B/op          0 allocs/op
ok      so/test 7.026s
$

5
यदि आप लूप्स को 10 पर सेट करते हैं तो उस बेंचमार्क को पुनः प्रयास करें जिसे आप एक चिह्नित अंतर देखेंगे। मेरी मशीन पर ForClause में 5.6 ns लगते हैं जबकि Iter में 15.4 ns लगते हैं, इसलिए आवंटनकर्ता को कॉल करना (भले ही यह कुछ भी आवंटित न करने के लिए पर्याप्त चतुर है) अभी भी 10ns और अतिरिक्त I-कैश बस्टिंग कोड का एक पूरा ढेर खर्च होता है।
निक क्रेग-वुड

मेरे जवाब में आपके द्वारा बनाए गए पैकेज और संदर्भ के लिए मुझे आपके बेंचमार्क और समालोचकों को देखने में दिलचस्पी होगी ।
क्रिस रेडफोर्ड

5

हालांकि मैं इस भाषा सुविधा की कमी के बारे में आपकी चिंता के साथ, आप शायद केवल एक सामान्य forलूप का उपयोग करना चाहते हैं । और आप शायद इससे अधिक ठीक होंगे कि आप जितना सोचते हैं उससे अधिक गो कोड लिखते हैं।

मैंने इस पुनरावृति पैकेज को लिखा है - जो एक साधारण, मुहावरेदार forपाश द्वारा समर्थित है , जो कि https://github.com/bradfitz/iterchan int में पाए गए डिज़ाइन पर सुधार करने के प्रयास में मानों को लौटाता है , जिसकी ओर इशारा किया गया है कैशिंग और प्रदर्शन के मुद्दे, साथ ही साथ एक चतुर, लेकिन अजीब और अनपेक्षित कार्यान्वयन। मेरा अपना संस्करण उसी तरह संचालित होता है:

package main

import (
    "fmt"
    "github.com/drgrib/iter"
)

func main() {
    for i := range iter.N(10) {
        fmt.Println(i)
    }
}

हालांकि, बेंचमार्किंग से पता चला कि एक चैनल का उपयोग बहुत महंगा विकल्प था। 3 तरीकों की तुलना, जो iter_test.goमेरे पैकेज से उपयोग करके चलाए जा सकते हैं

go test -bench=. -run=.

इसकी प्रदर्शन क्षमता कितनी खराब है

BenchmarkForMany-4                   5000       329956 ns/op           0 B/op          0 allocs/op
BenchmarkDrgribIterMany-4               5    229904527 ns/op         195 B/op          1 allocs/op
BenchmarkBradfitzIterMany-4          5000       337952 ns/op           0 B/op          0 allocs/op

BenchmarkFor10-4                500000000         3.27 ns/op           0 B/op          0 allocs/op
BenchmarkDrgribIter10-4            500000      2907 ns/op             96 B/op          1 allocs/op
BenchmarkBradfitzIter10-4       100000000        12.1 ns/op            0 B/op          0 allocs/op

इस प्रक्रिया में, यह मानदंड यह भी दर्शाता है कि लूप के आकार के लिए bradfitzअंतर्निहित forक्लॉज की तुलना में समाधान अंडरपरफॉर्म कैसे करता है 10

संक्षेप में, पायथन और रूबी में पाए जाने वाले के forलिए एक सरल वाक्यविन्यास प्रदान करते हुए बिल्ट-इन क्लॉज के प्रदर्शन को डुप्लिकेट करने के लिए अब तक कोई रास्ता नहीं [0,n)मिला है।

जो एक शर्म की बात है क्योंकि गो टीम के लिए एक लाइन को बदलने के लिए संकलक में एक सरल नियम जोड़ना आसान होगा

for i := range 10 {
    fmt.Println(i)
}

के रूप में एक ही मशीन कोड के लिए for i := 0; i < 10; i++

हालाँकि, निष्पक्ष होने के लिए, अपने स्वयं के लिखने के बाद iter.N(लेकिन इसे बेंचमार्क करने से पहले), मैं हाल ही में लिखे गए कार्यक्रम के माध्यम से उन सभी जगहों को देखने के लिए वापस चला गया जो मैं इसका उपयोग कर सकता था। वास्तव में कई नहीं थे। मेरे कोड के एक गैर-महत्वपूर्ण अनुभाग में केवल एक ही स्थान था, जहां मैं अधिक पूर्ण, डिफ़ॉल्ट forखंड के बिना प्राप्त कर सकता था ।

इसलिए जब यह लग सकता है कि यह सिद्धांत में भाषा के लिए एक बड़ी निराशा है, तो आप पा सकते हैं - जैसे मैंने किया था - कि आपको वास्तव में अभ्यास में इसकी आवश्यकता नहीं है। जैसे रोब पाइक को जेनेरिक के लिए कहने के लिए जाना जाता है, आप वास्तव में इस सुविधा को याद नहीं कर सकते हैं जितना आप सोचते हैं कि आप करेंगे।


1
चलना के लिए एक चैनल का उपयोग करना बहुत महंगा है; गोरआउट और चैनल सस्ते हैं, वे मुफ्त नहीं हैं। यदि चैनल पर पुनरावृत्ति सीमा जल्दी समाप्त हो जाती है, तो गोरोइनिन कभी समाप्त नहीं होती है (एक गोरोइन रिसाव)। आइटर विधि को वेक्टर पैकेज से हटा दिया गया था । " कंटेनर / वेक्टर: इंटरफ़ेस से आईटर () हटाएं (Iter () कॉल करने के लिए लगभग सही तंत्र नहीं है)। " आपका पुनरावृत्ति समाधान हमेशा सबसे महंगा है।
पेट्रोएस

4

यदि आप किसी श्रेणी w / o का उपयोग करके और सूचकांकों या किसी अन्य चीज़ पर बस चलना चाहते हैं, तो यह कोड नमूना मेरे लिए ठीक काम करता है। कोई अतिरिक्त घोषणा की जरूरत है, नहीं _। हालाँकि प्रदर्शन की जाँच नहीं की गई है।

for range [N]int{} {
    // Body...
}

PS GoLang में पहले दिन। अगर यह गलत तरीका है तो कृपया आलोचना करें।


अब तक (संस्करण 1.13.6), यह काम नहीं करता है। non-constant array boundमुझ पर फेंक रहे हैं।
डब्ल्यूएचएस

1

आप github.com/wushilin/stream को भी देख सकते हैं

यह java.util.stream की अवधारणा की तरह एक आलसी धारा है।

// It doesn't really allocate the 10 elements.
stream1 := stream.Range(0, 10)

// Print each element.
stream1.Each(print)

// Add 3 to each element, but it is a lazy add.
// You only add when consume the stream
stream2 := stream1.Map(func(i int) int {
    return i + 3
})

// Well, this consumes the stream => return sum of stream2.
stream2.Reduce(func(i, j int) int {
    return i + j
})

// Create stream with 5 elements
stream3 := stream.Of(1, 2, 3, 4, 5)

// Create stream from array
stream4 := stream.FromArray(arrayInput)

// Filter stream3, keep only elements that is bigger than 2,
// and return the Sum, which is 12
stream3.Filter(func(i int) bool {
    return i > 2
}).Sum()

उम्मीद है की यह मदद करेगा


0
package main

import "fmt"

func main() {

    nums := []int{2, 3, 4}
    for _, num := range nums {
       fmt.Println(num, sum)    
    }
}

1
भविष्य के पाठकों को इसके अर्थ को बेहतर ढंग से समझने में मदद करने के लिए अपने कोड में कुछ संदर्भ जोड़ें।
ग्रांट मिलर

3
यह क्या है? योग परिभाषित नहीं है।
naftalimich

0

मैंने गोलंग में एक पैकेज लिखा है जो पायथन के रेंज फंक्शन की नकल करता है:

पैकेज https://github.com/thedevsaddam/iter

package main

import (
    "fmt"

    "github.com/thedevsaddam/iter"
)

func main() {
    // sequence: 0-9
    for v := range iter.N(10) {
        fmt.Printf("%d ", v)
    }
    fmt.Println()
    // output: 0 1 2 3 4 5 6 7 8 9

    // sequence: 5-9
    for v := range iter.N(5, 10) {
        fmt.Printf("%d ", v)
    }
    fmt.Println()
    // output: 5 6 7 8 9

    // sequence: 1-9, increment by 2
    for v := range iter.N(5, 10, 2) {
        fmt.Printf("%d ", v)
    }
    fmt.Println()
    // output: 5 7 9

    // sequence: a-e
    for v := range iter.L('a', 'e') {
        fmt.Printf("%s ", string(v))
    }
    fmt.Println()
    // output: a b c d e
}

नोट: मैंने मनोरंजन के लिए लिखा है! Btw, कभी-कभी यह सहायक हो सकता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.