জাভাতে কোনও অ্যারের একটি অংশ গাদা করে একটি নতুন অ্যারে তৈরি না করে


181

আমি জাভাতে এমন একটি পদ্ধতির সন্ধান করছি যা কোনও অ্যারের অংশকে ফিরিয়ে দেবে। একটি উদাহরণ হ'ল একটি বাইট অ্যারের 4 র্থ এবং 5 ম বাইট সমন্বিত বাইট অ্যারে পাওয়া। আমি হ্যাপ মেমোরিতে একটি নতুন বাইট অ্যারে তৈরি করতে চাই না কেবল এটি করতে। এই মুহূর্তে আমার কাছে নিম্নলিখিত কোড রয়েছে:

doSomethingWithTwoBytes(byte[] twoByteArray);

void someMethod(byte[] bigArray)
{
      byte[] x = {bigArray[4], bigArray[5]};
      doSomethingWithTwoBytes(x);
}

doSomething(bigArray.getSubArray(4, 2))উদাহরণস্বরূপ, যেখানে 4 অফসেট এবং 2 দৈর্ঘ্য যেখানে কেবল করার কোনও উপায় ছিল কিনা তা জানতে চাই ।


1
সি ++ তে কিছু জেএনআই যাদু করার বিষয়ে কী? জিসি পিওভের কাছ থেকে কোনও বিপর্যয় হতে পারে?
অ্যালিকেলিন-কিলাকা 8'15

এটি কি আদিম বাইটের অ্যারে হতে হবে?
এমপি কোরস্টানজে

উত্তর:


185

দাবি অস্বীকার: এই উত্তর প্রশ্নের সীমাবদ্ধতার সাথে সামঞ্জস্য করে না:

আমি হ্যাপ মেমোরিতে একটি নতুন বাইট অ্যারে তৈরি করতে চাই না কেবল এটি করতে।

( সত্যি বলতে, আমি আমার উত্তর মুছে ফেলার যোগ্য বলে মনে করি। @ অনন্য 72 এর উত্তর সঠিক Im ইমাম এই সম্পাদনাটি কিছুটা বসতে দিন এবং তারপরে আমি এই উত্তরটি মুছব ))


অতিরিক্ত গাদা বরাদ্দ ছাড়াই অ্যারে দিয়ে সরাসরি এটি করার কোনও উপায় আমি জানি না, তবে সাব-লিস্ট র‌্যাপার ব্যবহার করে অন্য উত্তরগুলিতে কেবল মোড়কের জন্য অতিরিক্ত বরাদ্দ রয়েছে - তবে অ্যারে নয় - যা ক্ষেত্রে কার্যকর হবে একটি বড় অ্যারে।

এটি বলেছিল, যদি কেউ ব্রিভিটি খুঁজছেন, তবে Arrays.copyOfRange()জাভা Java (2006 সালের শেষের দিকে) ইউটিলিটি পদ্ধতিটি চালু করা হয়েছিল:

byte [] a = new byte [] {0, 1, 2, 3, 4, 5, 6, 7};

// get a[4], a[5]

byte [] subArray = Arrays.copyOfRange(a, 4, 6);

10
এটি এখনও গতিশীলভাবে একটি নতুন মেমরি বিভাগকে বরাদ্দ করে এবং এতে রেঞ্জটি অনুলিপি করে।
ড্যান

4
থ্যাঙ্কস ড্যান - আমি অবহেলা করেছি যে ওপি নতুন অ্যারে তৈরি করতে চায় না এবং আমি এর বাস্তবায়নের দিকে তাকাইনি copyOfRange। যদি এটি ক্লোজ-সোর্স হত তবে এটি পাস হতে পারে। :)
ডেভিড জে লিজজেউস্কি

7
আমি মনে করি প্রচুর লোকেরা একটি অ্যারে থেকে একটি সাব অ্যারে তৈরি করতে চায় এবং এটি আরও কিছু স্মৃতি ব্যবহার করে তা নিয়ে চিন্তিত নয়। তারা এই প্রশ্নটি জুড়ে আসে এবং তারা যে উত্তর চায় তা পেতে পারে - সুতরাং দয়া করে এটি কার্যকর হিসাবে মুছবেন না - আমি মনে করি এটি ঠিক আছে।
একাকী কোডার

2
আসলে, কপিঅফরেঞ্জ এখনও নতুন মেমরি বিভাগ বরাদ্দ করে
কেভিঙ্গো সোসাই

167

Arrays.asList(myArray)নতুন প্রতিনিধি ArrayList(myArray), যা অ্যারে অনুলিপি করে না তবে কেবল রেফারেন্স সঞ্চয় করে। এর List.subList(start, end)পরে ব্যবহার করে এমনটি তৈরি হয় SubListযা কেবলমাত্র মূল তালিকার উল্লেখ করে (যা এখনও অ্যারের উল্লেখ করে)। অ্যারে বা এর বিষয়বস্তুগুলির কোনও অনুলিপি করা হয়নি, কেবল মোড়ক তৈরি করা, এবং জড়িত সমস্ত তালিকাগুলি মূল অ্যারে দ্বারা ব্যাকড হয় না। (আমি ভেবেছিলাম এটি ভারী হবে)


9
স্পষ্ট করার জন্য, এটি Arraysবিভ্রান্তিকরভাবে ডাকা একটি প্রাইভেট ক্লাসের প্রতিনিধি ArrayList, কিন্তু যা সত্যই Listএকটি অ্যারের কাছাকাছি, java.util.ArrayListযার বিপরীতে একটি অনুলিপি তৈরি করা হবে। কোনও নতুন বরাদ্দ (তালিকার বিষয়বস্তুগুলির), এবং কোনও তৃতীয় পক্ষের নির্ভরতা নেই। এটি, আমি বিশ্বাস করি, সবচেয়ে সঠিক উত্তর।
dimo414

28
প্রকৃতপক্ষে, এটি ওপি যেমনটি চেয়েছিল ( byte[]তার ক্ষেত্রে) আদিম ধরণের অ্যারেগুলির জন্য কাজ করবে না । আপনি সব পাবেন List<byte[]>। এবং এতে পরিবর্তন byte[] bigArrayকরা Byte[] bigArrayএকটি উল্লেখযোগ্য স্মৃতি ওভারহেড চাপিয়ে দিতে পারে।
দিমিত্রি অ্যাভটনোমোভ

2
সত্য যা ইচ্ছা তা অর্জনের একমাত্র উপায় sun.misc.Unsafeক্লাসের মাধ্যমে ।
দিমিত্রি অ্যাভটনোমভ

39

যদি আপনি কোনও পয়েন্টার শৈলী আলিয়াজিং পদ্ধতির সন্ধান করেন, যাতে আপনার এমনকি জায়গা বরাদ্দ এবং ডেটা অনুলিপি করার প্রয়োজন হয় না তবে আমি বিশ্বাস করি আপনি ভাগ্য থেকে দূরে রয়েছেন।

System.arraycopy() আপনার উত্স থেকে গন্তব্যে অনুলিপি করবে, এবং দক্ষতা এই ইউটিলিটির জন্য দাবি করা হয়েছে। আপনাকে গন্তব্য অ্যারে বরাদ্দ করতে হবে না।


3
হ্যাঁ, আমি কোনও ধরণের পয়েন্টার পদ্ধতির জন্য আশা করছিলাম যেহেতু আমি গতিশীলভাবে মেমরি বরাদ্দ করতে চাই না। তবে দেখে মনে হচ্ছে আমি যা করতে যাচ্ছি।
jbu

1
@ অনন্য 72 এর পরামর্শ অনুসারে, বিভিন্ন জাভা তালিকা / অ্যারে প্রকারের প্রয়োগের ক্ষেত্রে সূক্ষ্মতা কাজে লাগিয়ে আপনি যা চান তা করার উপায় রয়েছে। এটি সম্ভব হয়েছে বলে মনে হচ্ছে, কেবল একটি সুস্পষ্ট পদ্ধতিতে নয় এবং এটি আমাকে খুব বেশি নির্ভর করতে দ্বিধা বোধ করে ...
অ্যান্ড্রু

array*copy*()একই স্মৃতি পুনরায় ব্যবহার করা উচিত কেন ? একজন কলকারী যা আশা করবেন তার ঠিক বিপরীতটি কি এটি নয়?
প্যাট্রিক ফ্যাভের

23

একটি উপায় হ'ল অ্যারেটি মোড়ানো java.nio.ByteBuffer, নিখুঁত পুট / ফাংশনগুলি পাওয়া এবং সাবহারে কাজ করার জন্য বাফারটি স্লাইস করা।

এই ক্ষেত্রে:

doSomething(ByteBuffer twoBytes) {
    byte b1 = twoBytes.get(0);
    byte b2 = twoBytes.get(1);
    ...
}

void someMethod(byte[] bigArray) {
      int offset = 4;
      int length = 2;
      doSomething(ByteBuffer.wrap(bigArray, offset, length).slice());
}

মনে রাখবেন যে আপনাকে উভয়কেই কল করতে হবে wrap()এবং slice()যেহেতু wrap()নিজেই কেবল আপেক্ষিক পুট / ফাংশনগুলিকে প্রভাবিত করে, পরম বিষয়গুলি নয়।

ByteBuffer বুঝতে কিছুটা জটিল হতে পারে, তবে সম্ভবত এটি দক্ষতার সাথে বাস্তবায়িত হয় এবং শেখার পক্ষে উপযুক্ত।


1
এটি আরও লক্ষণীয় যে বাইটবফার অবজেক্টগুলি মোটামুটি সহজেই ডিকোড করা যায়:StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buffer, 0, readBytes))
স্কিরিল

@ সোলম্যান ব্যাখ্যার জন্য ধন্যবাদ, তবে একটি প্রশ্ন কি এটি ব্যবহারের চেয়ে দক্ষ Arrays.copyOfRange?
ucMedia

1
দ্বিগুণ বাইট অ্যারের জন্য @ ইউকিমিডিয়া Arrays.copyOfRangeসম্ভবত আরও দক্ষ। সাধারণত, আপনার নির্দিষ্ট ব্যবহারের ক্ষেত্রে আপনাকে মাপতে হবে।
সোলম্যান

20

Java.nio.Buffer এর ব্যবহার করুন। এটি বিভিন্ন আদিম ধরণের বাফারগুলির জন্য হালকা ওজনের একটি রেভার এবং কাটা, অবস্থান, রূপান্তর, বাইট ক্রম ইত্যাদি পরিচালনা করতে সহায়তা করে

যদি আপনার বাইটস স্ট্রিম থেকে উদ্ভূত হয় তবে এনআইও বাফাররা "ডাইরেক্ট মোড" ব্যবহার করতে পারে যা দেশীয় সম্পদের সাহায্যে একটি বাফার তৈরি করে। এটি অনেক ক্ষেত্রে কর্মক্ষমতা উন্নত করতে পারে।


14

আপনি অ্যাপাচি কমনে অ্যারে ইউটিলস.সুবারে ব্যবহার করতে পারেন । নিখুঁত নয় System.arraycopy. তবে ডাউনসাইডের চেয়ে খানিকটা স্বজ্ঞাত হ'ল এটি আপনার কোডের সাথে অন্য একটি নির্ভরতা প্রবর্তন করে।


23
এটি জাভা 1.6
অ্যারেসকপি

10

আমি সাবলিস্ট উত্তরটি ইতিমধ্যে এখানে দেখতে পেয়েছি, তবে এখানে কোডটি প্রমাণ করে যে এটি সত্যিকারের সাবলিস্ট, কোনও অনুলিপি নয়:

public class SubListTest extends TestCase {
    public void testSubarray() throws Exception {
        Integer[] array = {1, 2, 3, 4, 5};
        List<Integer> list = Arrays.asList(array);
        List<Integer> subList = list.subList(2, 4);
        assertEquals(2, subList.size());
        assertEquals((Integer) 3, subList.get(0));
        list.set(2, 7);
        assertEquals((Integer) 7, subList.get(0));
    }
}

তবে অ্যারে দিয়ে সরাসরি এটি করার ভাল উপায় আছে বলে আমি বিশ্বাস করি না।



6

একটি বিকল্পটি হ'ল পুরো অ্যারে এবং সূচনা এবং শেষ সূচকগুলি পাস করা হবে এবং পুরো অ্যারেটিকে পুনরাবৃত্তি করার পরিবর্তে এর মধ্যে পুনরাবৃত্তি হবে।

void method1(byte[] array) {
    method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
    for ( int i = start; i <= end; i++ ) {
        ....
    }
}

6

Listআপনার সঙ্গে ব্যবহার এবং কাজ করার অনুমতি দেয় subListস্বচ্ছভাবে কিছু। আদিম অ্যারেগুলির জন্য আপনাকে কোনও ধরণের অফসেট - সীমাবদ্ধ রাখার প্রয়োজন হয়। ByteBufferআমি শুনেছি একই বিকল্প আছে।

সম্পাদনা: আপনি যদি দরকারী পদ্ধতির দায়িত্বে থাকেন তবে আপনি কেবল এটি সীমানা দিয়ে সংজ্ঞায়িত করতে পারেন (যেমন জাভাতে অনেক অ্যারে সম্পর্কিত পদ্ধতিতে সম্পন্ন হয়েছে:

doUseful(byte[] arr, int start, int len) {
    // implementation here
}
doUseful(byte[] arr) {
    doUseful(arr, 0, arr.length);
}

এটি পরিষ্কার নয়, তবে আপনি যদি অ্যারে উপাদানগুলিতে নিজেরাই কাজ করেন, যেমন আপনি কোনও কিছু গণনা করে ফলাফলটি আবার লিখে রাখেন?


6

জাভা রেফারেন্স সর্বদা একটি বস্তুর দিকে নির্দেশ করে। অবজেক্টটির একটি শিরোনাম রয়েছে যা অন্যান্য জিনিসের মধ্যে কংক্রিটের ধরণ সনাক্ত করে (যাতে ক্যাসেটগুলি ব্যর্থ হতে পারে ClassCastException)। অ্যারেগুলির জন্য, অবজেক্টের শুরুতে দৈর্ঘ্যও অন্তর্ভুক্ত থাকে, ডেটা মেমরির সাথে সাথেই অনুসরণ করা হয় (প্রযুক্তিগতভাবে একটি বাস্তবায়ন যা খুশি তা করতে মুক্ত, তবে এটি অন্য কোনও কিছু করতে বুদ্ধিমান হবে)। সুতরাং, আপনার কাছে একটি রেফারেন্স থাকতে পারে যা কোথাও অ্যারেতে নির্দেশ করে।

সি পয়েন্টারে কোথাও এবং যেকোন কিছুতেও নির্দেশ করুন এবং আপনি একটি অ্যারের মাঝখানে নির্দেশ করতে পারেন। তবে আপনি নিরাপদে কাস্ট করতে পারবেন না বা অ্যারে কত দীর্ঘ তা সন্ধান করতে পারবেন না। ডি-তে পয়েন্টারটিতে মেমরি ব্লক এবং দৈর্ঘ্যের একটি অফসেট থাকে (বা সমতুল্যভাবে শেষের দিকে একটি পয়েন্টার থাকে, বাস্তবায়ন আসলে কী করে তা আমি মনে করতে পারি না)। এটি ডি কে অ্যারে স্লাইস করতে দেয়। সি ++ এ আপনার দুটি পুনরাবৃত্তি শুরু এবং শেষের দিকে নির্দেশ করবে তবে সি ++ এর মতো কিছুটা বিশ্রী od

সুতরাং জাভা ফিরে পেয়ে, না আপনি পারবেন না। উল্লিখিত হিসাবে, এনআইও ByteBufferআপনাকে একটি অ্যারে মোড়ানোর অনুমতি দেয় এবং তারপরে এটি কেটে ফেলা যায়, তবে একটি বিশ্রী ইন্টারফেস দেয় gives আপনি অবশ্যই অনুলিপি করতে পারেন, যা সম্ভবত আপনি যা ভাবেন তার চেয়ে খুব দ্রুত। আপনি আপনার নিজের Stringমতো বিমূর্ততা প্রবর্তন করতে পারেন যা আপনাকে একটি অ্যারের টুকরো টুকরো করতে দেয় (বর্তমান সূর্যের প্রয়োগের Stringএকটি char[]রেফারেন্স প্লাস একটি প্রারম্ভের অফসেট এবং দৈর্ঘ্য রয়েছে, উচ্চ কার্য সম্পাদনের বাস্তবায়ন কেবল আছে char[])। byte[]নিম্ন স্তরের, তবে যে ক্লাস-ভিত্তিক বিমূর্ততা আপনি রেখেছেন তা জেডিকে ((সম্ভবত) অবধি সিনট্যাক্সের একটি ভয়াবহ জগাখিচুড়ি করতে চলেছে।


কেন এটি অসম্ভব হবে তা ব্যাখ্যা করার জন্য ধন্যবাদ। বিটিডব্লিউ, স্ট্রিং এখন substringহটস্পট-এ অনুলিপি করেছেন (ভুলে যা যা তৈরি করুন এটি পরিবর্তিত হয়েছে)। আপনি কেন বলছেন যে জেডিকে 7 বাইটবফারের চেয়ে আরও ভাল সিনট্যাক্সের অনুমতি দেবে?
আলেকসান্দ্র ডাবিনস্কি

@ আলেকসান্ডারডুবিনস্কি লেখার সময় দেখে মনে হচ্ছিল জাভা এসই 7 []ব্যবহারকারী Listএবং সংজ্ঞায়িত ধরণের যেমন অ্যারে চিহ্নিতকরণের অনুমতি দিচ্ছে ByteBuffer। এখনও অপেক্ষা করা হচ্ছে ...
টম হাটিন -

2

@ অনন্য 72২ উত্তরটিকে একটি সাধারণ ফাংশন বা লাইন হিসাবে, আপনার অবজেক্টটি প্রতিস্থাপনের প্রয়োজন হতে পারে, আপনার পছন্দ মতো 'শ্রেণি' করতে চান class বিভিন্ন প্রয়োজন অনুসারে দুটি ভেরিয়েন্ট দেওয়া হয়।

/// Extract out array from starting position onwards
public static Object[] sliceArray( Object[] inArr, int startPos ) {
    return Arrays.asList(inArr).subList(startPos, inArr.length).toArray();
}

/// Extract out array from starting position to ending position
public static Object[] sliceArray( Object[] inArr, int startPos, int endPos ) {
    return Arrays.asList(inArr).subList(startPos, endPos).toArray();
}

1

পাতলা Listমোড়কের কীভাবে ?

List<Byte> getSubArrayList(byte[] array, int offset, int size) {
   return new AbstractList<Byte>() {
      Byte get(int index) {
         if (index < 0 || index >= size) 
           throw new IndexOutOfBoundsException();
         return array[offset+index];
      }
      int size() {
         return size;
      }
   };
}

(অপরীক্ষিত)


এটিতে বাইটগুলির বক্সিং-আনবক্সিং করতে হবে। ধীর হতে পারে।
এমপি কোরস্টঞ্জে

@ এমপিকোর্স্টানজে: ওরেবল জাভা গ্রন্থাগারে Byteসমস্ত byteমানগুলির জন্য ক্যাশে করা হয়। সুতরাং বক্সিং ওভারহেড বরং ধীর হওয়া উচিত।
লিই

1

আমার একটি অ্যারের শেষ প্রান্তে পুনরাবৃত্তি হওয়া দরকার এবং অ্যারেটি অনুলিপি করতে চাইনি। আমার পদ্ধতির ছিল অ্যারে ধরে একটি Iteable করা।

public static Iterable<String> sliceArray(final String[] array, 
                                          final int start) {
  return new Iterable<String>() {
    String[] values = array;
    int posn = start;

    @Override
    public Iterator<String> iterator() {
      return new Iterator<String>() {
        @Override
        public boolean hasNext() {
          return posn < values.length;
        }

        @Override
        public String next() {
          return values[posn++];
        }

        @Override
        public void remove() {
          throw new UnsupportedOperationException("No remove");
        }
      };
    }
  };
}

-1

এটি অ্যারেএসকপি-অফিফ্রেঞ্জের চেয়ে কিছুটা কম ওজনের - কোনও ব্যাপ্তি বা নেতিবাচক নয়

public static final byte[] copy(byte[] data, int pos, int length )
{
    byte[] transplant = new byte[length];

    System.arraycopy(data, pos, transplant, 0, length);

    return transplant;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.