एक सरणी की प्रतिलिपि बनाएँ


345

मेरे पास एक सरणी है aजिसे लगातार अपडेट किया जा रहा है। चलिए बताते हैं a = [1,2,3,4,5]। मुझे इसकी एक सटीक डुप्लिकेट प्रतिलिपि बनाने aऔर इसे कॉल करने की आवश्यकता है b। अगर aबदलना था [6,7,8,9,10], तब bभी होना चाहिए [1,2,3,4,5]। इसे करने का बेहतरीन तरीका क्या है? मैंने एक forलूप की कोशिश की जैसे:

for(int i=0; i<5; i++) {
    b[i]=a[i]
}

लेकिन यह सही ढंग से काम नहीं करता है। कृपया गहरी कॉपी जैसे उन्नत शब्दों का उपयोग न करें, आदि, क्योंकि मुझे नहीं पता कि इसका क्या मतलब है।

जवाबों:


558

आप System.arraycopy () का उपयोग करके देख सकते हैं

int[] src  = new int[]{1,2,3,4,5};
int[] dest = new int[5];

System.arraycopy( src, 0, dest, 0, src.length );

लेकिन, ज्यादातर मामलों में क्लोन () का उपयोग करना बेहतर होगा:

int[] src = ...
int[] dest = src.clone();

9
पहिए को रीवाइंड करने के लिए +1 नहीं। और जहाँ तक मुझे पता है, यह समाधान तेजी से आप सरणी कॉपी में प्राप्त कर सकते हैं।
फेलिपेम्स इलेक्ट्रान्स

6
दोनों क्लोन और arraycopy देशी हैं। मुझे उम्मीद है कि क्लोन में तेजी से बढ़त होगी। यह नहीं कि अंतर मायने रखता है।
MeBigFatGuy

5
@Felipe, @MeBigFatGuy - केवल एक बड़े सरणी के लिए। छोटे सरणी के लिए, सेटअप ओवरहेड्स के कारण एक कॉपी लूप तेज हो सकता है। यदि आप के लिए javadoc को System.arraycopyदेखते हैं, तो आप देखेंगे कि विधि को शुरू होने से पहले विभिन्न चीजों की जांच करने की आवश्यकता है। स्थिर चेक प्रकारों के आधार पर, इनमें से कुछ चेक कॉपी लूप के साथ अनावश्यक हैं।
स्टीफन सी

7
@FelipeHummel, @MeBigFatGuy, @StephenC - यहाँ उत्तर में वर्णित सरणी कॉपी विधियों का प्रदर्शन परीक्षण है। उस सेट अप में, clone()250 000 तत्वों के लिए सबसे तेज़ निकला।
एडम

6
यह देखना निराशाजनक है कि यहां सभी चर्चा सूक्ष्म प्रदर्शन के मुद्दों के बारे में है, जो समय के 99.999% हैं, इससे कोई फर्क नहीं पड़ता। अधिक महत्वपूर्ण बात यह है कि src.clone()अधिक पठनीय है और नए सरणी को आवंटित करने और करने की तुलना में त्रुटि के लिए बहुत कम अवसर है arraycopy। (और तेज भी होता है।)
ब्रायन गोएटज़

231

आप उपयोग कर सकते हैं

int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();

भी।


6
मैं ओपी की बात को साफ कर रहा हूं कि: " यदि A को [6,7,8,9,10] में बदलना है, तो B को अभी भी 1,2,3,4,5] होना चाहिए ।" ओपी ने कहा कि उसने लूप का उपयोग करने की कोशिश की, लेकिन उसके लिए काम नहीं किया।
हैरी जॉय

15
डाली अनावश्यक है; एक अच्छा स्थिर विश्लेषक इसके बारे में चेतावनी देगा। लेकिन क्लोनिंग निश्चित रूप से एक सरणी की नई प्रतिलिपि बनाने का सबसे अच्छा तरीका है।
इरिकसन

5
@MeBigFatGuy - ओपी का उपयोग-मामला एक ही सरणी में बार-बार कॉपी करने के लिए मजबूर करता है, इसलिए क्लोन काम नहीं करता है।
स्टीफन सी

4
@ स्टीफन सी, मैंने ऐसा नहीं पढ़ा। मैंने अभी पढ़ा है कि वह एक प्रति चाहता है, और फिर बाद में बार-बार नॉन-स्टैडेड संस्करण को अपडेट करेगा।
MeBigFatGuy

4
@MeBigFatGuy - उन्होंने कहा "मेरे पास एक ए है जो लगातार अपडेट किया जा रहा है।" । हो सकता है कि मैं इसमें बहुत अधिक पढ़ रहा हूं, लेकिन मैं इसे इस रूप में लेता हूं कि वह बार-बार ए से बी को भी कॉपी कर रहा है।
स्टीफन C

184

यदि आप इसकी एक प्रतिलिपि बनाना चाहते हैं:

int[] a = {1,2,3,4,5};

जाने का यह रास्ता है:

int[] b = Arrays.copyOf(a, a.length);

Arrays.copyOfa.clone()छोटे सरणियों की तुलना में तेज हो सकता है । दोनों तत्व समान रूप से तेजी से प्रतिलिपि बनाते हैं, लेकिन क्लोन () रिटर्न करता है Objectइसलिए संकलक को एक अंतर्निहित डाली सम्मिलित करना है int[]। आप इसे बाइटकोड में देख सकते हैं, कुछ इस तरह से:

ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2

62

Http://www.journaldev.com/753/how-to-copy-arrays-in-java से अच्छी व्याख्या

जावा ऐरे कॉपी के तरीके

Object.clone () : ऑब्जेक्ट क्लास क्लोन () विधि प्रदान करता है और चूँकि java में भी एक ऑब्जेक्ट है, आप इस विधि का उपयोग फुल एरे कॉपी प्राप्त करने के लिए कर सकते हैं। यदि आप सरणी की आंशिक प्रतिलिपि चाहते हैं तो यह विधि आपके अनुरूप नहीं होगी।

System.arraycopy () : सिस्टम क्लास arraycopy () किसी ऐरे की आंशिक कॉपी करने का सबसे अच्छा तरीका है। यह स्रोत और गंतव्य सरणी अनुक्रमणिका स्थिति की प्रतिलिपि बनाने के लिए तत्वों की कुल संख्या निर्दिष्ट करने का एक आसान तरीका प्रदान करता है। उदाहरण के लिए System.arraycopy (स्रोत, 3, गंतव्य, 2, 5) स्रोत से गंतव्य तक 5 तत्वों की प्रतिलिपि बनाएगा, जो स्रोत के तीसरे सूचकांक से गंतव्य के 2 सूचकांक तक की शुरुआत करेगा।

Arrays.copyOf (): यदि आप किसी सरणी के पहले कुछ तत्वों या सरणी की पूर्ण प्रतिलिपि की प्रतिलिपि बनाना चाहते हैं, तो आप इस विधि का उपयोग कर सकते हैं। जाहिर है कि यह System.arraycopy () की तरह बहुमुखी नहीं है, लेकिन यह भ्रामक और उपयोग करने में आसान नहीं है।

Arr


35

मुझे लग रहा है कि ये सभी "किसी सरणी को कॉपी करने के बेहतर तरीके" वास्तव में आपकी समस्या को हल करने वाले नहीं हैं।

तुम कहो

मैं एक पाश के लिए कोशिश की तरह [...] लेकिन यह सही ढंग से काम नहीं कर रहा है?

उस पाश को देखते हुए, इसके काम न करने का कोई स्पष्ट कारण नहीं है ... जब तक कि:

  • आप किसी भी तरह aऔर bसरणियों को गड़बड़ कर दिया (उदाहरण के लिए aऔर bउसी सरणी को देखें), या
  • आपका एप्लिकेशन बहु-थ्रेडेड है और विभिन्न थ्रेड्स aएक साथ सरणी को पढ़ और अपडेट कर रहे हैं ।

या तो मामले में, नकल करने के वैकल्पिक तरीके अंतर्निहित समस्या को हल नहीं करेंगे।

पहले परिदृश्य के लिए फिक्स स्पष्ट है। दूसरे परिदृश्य के लिए आपको थ्रेड्स को सिंक्रनाइज़ करने के कुछ तरीके का पता लगाना होगा। परमाणु सरणी वर्ग मदद नहीं करते हैं क्योंकि उनके पास कोई परमाणु प्रतिलिपि बनाने वाले या क्लोन करने के तरीके नहीं हैं, लेकिन एक आदिम म्यूटेक्स का उपयोग करके सिंक्रनाइज़ेशन ट्रिक करेगा।

(आपके प्रश्न में संकेत हैं जो मुझे यह सोचने के लिए प्रेरित करते हैं कि यह वास्तव में धागा से संबंधित है; उदाहरण के लिए आपका कथन जो aलगातार बदल रहा है।)


2
सहमत .. शायद सच है।
MeBigFatGuy


9

सभी समाधान जो सरणी से लंबाई कहते हैं, अपने कोड को निरर्थक नल चेकर्सकॉन्डर उदाहरण में जोड़ें:

int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();

//What if array a comes as local parameter? You need to use null check:

public void someMethod(int[] a) {
    if (a!=null) {
        int[] b = Arrays.copyOf(a, a.length);
        int[] c = a.clone();
    }
}

मैं आपको पहिया का आविष्कार नहीं करने और उपयोगिता वर्ग का उपयोग करने की सलाह देता हूं, जहां सभी आवश्यक जांच पहले ही हो चुकी हैं। अपाचे कॉमन्स से ArrayUtils पर विचार करें। आप कोड छोटे हो जाते हैं:

public void someMethod(int[] a) {
    int[] b = ArrayUtils.clone(a);
}

अपाचे कॉमन्स आप वहाँ पा सकते हैं


8

आप भी इस्तेमाल कर सकते हैं Arrays.copyOfRange

उदाहरण :

public static void main(String[] args) {
    int[] a = {1,2,3};
    int[] b = Arrays.copyOfRange(a, 0, a.length);
    a[0] = 5;
    System.out.println(Arrays.toString(a)); // [5,2,3]
    System.out.println(Arrays.toString(b)); // [1,2,3]
}

यह विधि समान है Arrays.copyOf, लेकिन यह अधिक लचीली है। दोनों System.arraycopyहुड के नीचे उपयोग करते हैं।

देखें :


3

किसी सरणी की अशक्त-सुरक्षित प्रतिलिपि के लिए, आप Object.clone()इस उत्तर में दी गई विधि के साथ एक वैकल्पिक का उपयोग भी कर सकते हैं ।

int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);

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

1
मैं सहमत नहीं हूं कि सरणी इस निर्माण के लिए विशेष रूप से ढेर पर होगी। वास्तव में यह केवल जरूरत पड़ने पर क्लोन कहता है और Optionalमौजूदा सरणी के संदर्भ में ऑब्जेक्ट सिर्फ एक खाली वस्तु है। प्रदर्शन प्रभाव के बारे में, मैं कहूंगा कि यह कहना समय से पहले की बात है, यह वास्तव में एक प्रभाव है क्योंकि इस प्रकार का निर्माण जेवीएम के अंदर इनलाइनिंग के लिए एक अच्छा उम्मीदवार है और फिर अन्य तरीकों की तुलना में अधिक प्रभाव नहीं है। यह स्टाइल की बात है (कार्यात्मक प्रोग्रामिंग बनाम प्रक्रियात्मक प्रोग्रामिंग लेकिन न केवल) इसे अधिक जटिल या नहीं के रूप में माना जाता है।
निकोलस हेन्नेक्स

3

यदि आपको कच्ची सरणियों के साथ काम करना चाहिए और न ही ArrayListतब Arraysआपकी आवश्यकता है। यदि आप स्रोत कोड को देखते हैं, तो ये एक सरणी की प्रतिलिपि प्राप्त करने के लिए सबसे अच्छे तरीके हैं। उनके पास रक्षात्मक प्रोग्रामिंग का एक अच्छा हिस्सा है क्योंकि System.arraycopy()यदि आप इसे अतार्किक मापदंडों को खिलाते हैं तो विधि बहुत सारे अनियंत्रित अपवादों को फेंक देती है।

आप या तो उपयोग कर सकते हैं Arrays.copyOf()जो पहले से Nthतत्व से नए छोटे सरणी में कॉपी करेगा ।

public static <T> T[] copyOf(T[] original, int newLength)

निर्दिष्ट सरणी की प्रतिलिपि करता है, अशक्त या अशक्त (यदि आवश्यक हो) के साथ पैडिंग तो प्रतिलिपि में निर्दिष्ट लंबाई है। मूल सरणी और प्रतिलिपि दोनों में मान्य सभी सूचकांकों के लिए, दो सरणियों में समान मान होंगे। किसी भी सूचक के लिए जो कॉपी में मान्य हैं, लेकिन मूल नहीं हैं, कॉपी में शून्य होगा। इस तरह के सूचकांक मौजूद होंगे और यदि केवल निर्दिष्ट लंबाई मूल सरणी से अधिक हो। परिणामस्वरूप सरणी मूल सरणी के समान ही वर्ग है।

2770
2771    public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
2772        T[] copy = ((Object)newType == (Object)Object[].class)
2773            ? (T[]) new Object[newLength]
2774            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
2775        System.arraycopy(original, 0, copy, 0,
2776                         Math.min(original.length, newLength));
2777        return copy;
2778    }

या Arrays.copyOfRange()चाल भी करेंगे:

public static <T> T[] copyOfRange(T[] original, int from, int to)

निर्दिष्ट सरणी की निर्दिष्ट सीमा को एक नए सरणी में कॉपी करता है। रेंज का प्रारंभिक सूचकांक (से) शून्य और ओरिजिनल के बीच झूठ होना चाहिए। मूल [से] पर मूल्य को कॉपी के प्रारंभिक तत्व में रखा गया है (जब तक == मूल से। गति या == से)। मूल सरणी में बाद के तत्वों से मान कॉपी में बाद के तत्वों में रखा जाता है। रेंज का अंतिम इंडेक्स (टू), जो मूल से अधिक या उससे अधिक होना चाहिए, मूल से अधिक हो सकता है। लैंटर, जिस स्थिति में शून्य को कॉपी के सभी तत्वों में रखा जाता है जिसका इंडेक्स मूल से अधिक या उसके बराबर होता है। लंबाई - से। लौटे सरणी की लंबाई - से होगी। परिणामस्वरूप सरणी मूल सरणी के समान ही वर्ग है।

3035    public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
3036        int newLength = to - from;
3037        if (newLength < 0)
3038            throw new IllegalArgumentException(from + " > " + to);
3039        T[] copy = ((Object)newType == (Object)Object[].class)
3040            ? (T[]) new Object[newLength]
3041            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
3042        System.arraycopy(original, from, copy, 0,
3043                         Math.min(original.length - from, newLength));
3044        return copy;
3045    }

जैसा कि आप देख सकते हैं, ये दोनों System.arraycopyरक्षात्मक तर्क के साथ केवल आवरण कार्य हैं जो आप करने की कोशिश कर रहे हैं वह वैध है।

System.arraycopy सरणियों की नकल करने का सबसे तेज़ तरीका है।


0

मुझे 2 डी सरणियों के साथ एक समान समस्या थी और यहां समाप्त हुई। मैं मुख्य सरणी की प्रतिलिपि बना रहा था और आंतरिक सरणियों के मूल्यों को बदल रहा था, और जब दोनों प्रतियों में मान बदल गए तो आश्चर्य हुआ। मूल रूप से दोनों प्रतियाँ इंडिपेंडेंट थीं, लेकिन एक ही आंतरिक सरणियों के संदर्भ थे और मुझे जो मैं चाहता था उसे प्राप्त करने के लिए आंतरिक सरणियों की प्रतियों की एक सरणी बनाना था।

यह शायद ओपी की समस्या नहीं है, लेकिन मुझे उम्मीद है कि यह अभी भी मददगार हो सकता है।

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