تحويل مجموعة من اللطفاء البدائيين إلى قائمة بالجليد

StackOverflow https://stackoverflow.com/questions/754294

سؤال

قد يكون هذا قليلا من سؤال سهلة و Headdesk سؤالا، لكن محاولتي الأولى فشلت بشكل مدهش تماما في العمل. أردت أن تأخذ مجموعة من المسن البدائي وتحويلها إلى قائمة، والتي حاولت القيام بها مثل هذا:

long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!

ما هي الطريقة الصحيحة للقيام بذلك؟

هل كانت مفيدة؟

المحلول

لقد وجدت أنه مناسب للقيام باستخدام Apache Commons Lang Arrayutils (جافادوك, الاعتماد على مافن)

import org.apache.commons.lang3.ArrayUtils;
...
long[] input = someAPI.getSomeLongs();
Long[] inputBoxed = ArrayUtils.toObject(input);
List<Long> inputAsList = Arrays.asList(inputBoxed);

كما أن لديها API العكسي

long[] backToPrimitive = ArrayUtils.toPrimitive(objectArray);

تعديل: تم التحديث لتوفير تحويل كامل إلى قائمة كما هو مقترح حسب التعليقات والإصلاحات الأخرى.

نصائح أخرى

منذ Java 8 يمكنك الآن استخدام التدفقات لذلك:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));

halliDave. و jpalecek. احصل على الفكرة الصحيحة - تكرار حول مجموعة - لكنها لا تستفيد من ميزة توفرها ArrayList: حيث حجم القائمة معروف في هذه الحالة، يجب عليك تحديد ذلك عند إنشاء ArrayList.

List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
  list.add(n);

بهذه الطريقة، لا يتم إنشاء صفائف غير ضرورية فقط ليتم تجاهلها فقط من قبل ArrayList لأنها تتحول إلى أنها قصيرة جدا، ولا تضيع "فتحات فارغة" ل ArrayList المبالغة في تقدير متطلبات الفضاء. بالطبع، إذا استمرت في إضافة عناصر إلى القائمة، ستكون هناك حاجة إلى صفيف بدعم جديد.

أكثر من ذلك بكثير، ولكن هذا يعمل:

    List<Long> list = new ArrayList<Long>();
    for (long value : input) {
        list.add(value);
    }

في مثالك، يبدو أنه يتم تفسير Arrays.aslist () المدخلات كقائمة طويلة [] بدلا من قائمة طويلة من الأمان. مفاجأة بعض الشيء، بالتأكيد. الستوعية فقط لا يعمل بالطريقة التي تريدها في هذه الحالة.

كاحتمال آخر، مكتبة الجوافة يوفر هذا كما Longs.asList(), مع فصول فائدة مماثلة لأنواع البدائية الأخرى.

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);

لا، لا يوجد تحويل تلقائي من مجموعة من النوع البدائي إلى مجموعة أنواع المراجع الباطلة. يمكنك القيام به فقط

long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();

for(long l : input) lst.add(l);

طريقة أخرى مع جافا 8.

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));

سئل السؤال عن كيفية تحويل صفيف إلى قائمة. معظم الإجابات أظهرت حتى الآن كيفية إنشاء الجديد قائمة مع نفس المحتويات كصفيف، أو المشار إليها إلى مكتبات الطرف الثالث. ومع ذلك، هناك خيارات بسيطة ومدمجة لهذا النوع من التحويل. لقد تم بالفعل رسم بعضهم في إجابات أخرى (على سبيل المثال هذا). لكنني أرغب في الإشارة إلى درجات معينة ووضعها معينة من أجل التنفيذ هنا، وإظهار الفوائد المحتملة والعيوب والتحذير.

هناك فرقتين مهمتين على الأقل:

  • ما إذا كان ينبغي أن تكون القائمة الناتجة رأي على الصفيف أو ما إذا كان ينبغي أن يكون الجديد قائمة
  • ما إذا كان ينبغي أن تكون القائمة الناتجة قابل للتعديل أم لا

سيتم تلخيص الخيارات هنا بسرعة، ويظهر برنامج مثال كامل في أسفل هذه الإجابة.


إنشاء قائمة جديدة مقابل إنشاء رأي على الصفيف

عندما يجب أن تكون النتيجة الجديد قائمة، ثم يمكن استخدام واحدة من النهج من الإجابات الأخرى:

List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());

ولكن ينبغي للمرء أن ينظر في عيوب القيام بذلك: صفيف مع 1000000 long سوف تشغل القيم حوالي 8 ميغابايت من الذاكرة. القائمة الجديدة سوف أيضا احتل حوالي 8 ميغابايت. وبالطبع، يجب اجتياز الصفيف الكامل أثناء إنشاء هذه القائمة. في العديد من الحالات، فإن إنشاء قائمة جديدة ليس ضروريا ببساطة. بدلا من ذلك، يكفي إنشاء رأي على الصفيف:

// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }

// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);

(انظر المثال في الأسفل لتنفيذ toList طريقة)

آثار وجود رأي على المجموعة هي أن التغييرات في الصفيف ستكون مرئية في القائمة:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

System.out.println(list.get(1)); // This will print 34

// Modify the array contents:
array[1] = 12345;

System.out.println(list.get(1)); // This will now print 12345!

لحسن الحظ، إنشاء نسخة (أي، أ الجديد القائمة التي لا تتأثر بالتعديلات في الصفيف) من العرض تافهة:

List<Long> copy = new ArrayList<Long>(asList(array));

الآن، هذه نسخة حقيقية، أي ما يعادل ما يتحقق مع الحل القائم على الدفق الذي يظهر أعلاه.


خلق شيء قابل للتعديل عرض أو an. لا لبس فيه رأي

في كثير من الحالات، سيكون كافيا عندما تكون القائمة يقرأ فقط. وبعد غالبا ما لا يتم تعديل محتويات القائمة الناتجة، ولكن مرت فقط لمعالجة المصب التي يقرأها فقط القائمة.

السماح بتعديلات القائمة ترفع بعض الأسئلة:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

list.set(2, 34567);           // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null);            // What should happen here?
list.add(99999);              // Should this be possible?

من الممكن إنشاء عرض قائمة على الصفيف الذي هو قابل للتعديل. وبعد هذا يعني أن التغييرات في القائمة، مثل تحديد قيمة جديدة في مؤشر معين، ستكون مرئية في الصفيف.

ولكن لا يمكن إنشاء طريقة عرض قائمة قابلة للتعديل هيكليا. وبعد هذا يعني أنه من غير الممكن القيام بعمليات تؤثر على بحجم من القائمة. هذا هو ببساطة لأن حجم الأساس مجموعة مصفوفة لا يمكن تغييرها.


ما يلي هو ماكفي عرض خيارات التنفيذ المختلفة، والطرق الممكنة لاستخدام القوائم الناتجة:

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class PrimitiveArraysAsLists
{
    public static void main(String[] args)
    {
        long array[] = { 12, 34, 56, 78 };

        // Create VIEWS on the given array
        List<Long> list = asList(array);
        List<Long> unmodifiableList = asUnmodifiableList(array);

        // If a NEW list is desired (and not a VIEW on the array), this
        // can be created as well:
        List<Long> copy = new ArrayList<Long>(asList(array));

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value in the array. The changes will be visible
        // in the list and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 1 of the array...");
        array[1] = 34567;

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value of the list. The changes will be visible
        // in the array and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 2 of the list...");
        list.set(2, 56789L);

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        


        // Certain operations are not supported:
        try
        {
            // Throws an UnsupportedOperationException: This list is 
            // unmodifiable, because the "set" method is not implemented
            unmodifiableList.set(2, 23456L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }

        try
        {
            // Throws an UnsupportedOperationException: The size of the
            // backing array cannot be changed
            list.add(90L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }


        try
        {
            // Throws a NullPointerException: The value 'null' cannot be  
            // converted to a primitive 'long' value for the underlying array
            list.set(2, null);
        }
        catch (NullPointerException e)
        {
            System.out.println("Expected: " + e);
        }

    }

    /**
     * Returns an unmodifiable view on the given array, as a list.
     * Changes in the given array will be visible in the returned
     * list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asUnmodifiableList(long array[])
    {
        Objects.requireNonNull(array);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

    /**
     * Returns a view on the given array, as a list. Changes in the given 
     * array will be visible in the returned list, and vice versa. The
     * list does not allow for <i>structural modifications</i>, meaning
     * that it is not possible to change the size of the list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asList(long array[])
    {
        Objects.requireNonNull(array);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public Long set(int index, Long element)
            {
                long old = array[index];
                array[index] = element;
                return old;
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

}

يظهر إخراج المثال هنا:

array           : [12, 34, 56, 78]
list            : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 1 of the array...
array           : [12, 34567, 56, 78]
list            : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 2 of the list...
array           : [12, 34567, 56789, 78]
list            : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy            : [12, 34, 56, 78]
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.NullPointerException

أنا أكتب مكتبة صغيرة لهذه المشاكل:

long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();

في حال كنت تهتم بالتحقق من ذلك هنا.

الجمع بين إجابات بافل و توم نحصل على هذا

   @SuppressWarnings("unchecked")
    public static <T> List<T> asList(final Object array) {
        if (!array.getClass().isArray())
            throw new IllegalArgumentException("Not an array");
        return new AbstractList<T>() {
            @Override
            public T get(int index) {
                return (T) Array.get(array, index);
            }

            @Override
            public int size() {
                return Array.getLength(array);
            }
        };
    }

اخر طريق مع جافا 8.

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());

إذا كنت تريد دلالات مماثلة ل Arrays.asList ثم ستحتاج إلى كتابة (أو استخدام تطبيق عملاء شخص آخر) List (ربما من خلال ذلك AbstractList. وبعد يجب أن يكون لها نفس التنفيذ مثل Arrays.asList, ، مربع فقط وقيم Unbox.

يمكنك استخدام transmrorph. :

Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});

كما يعمل إذا كان المصدر عبارة عن مجموعة من Ints على سبيل المثال.

أعرف أن هذا السؤال قديم بما فيه الكفاية، ولكن ... يمكنك أيضا كتابة طريقة التحويل الخاصة بك:

@SuppressWarnings("unchecked")
public static <T> List<T> toList(Object... items) {

    List<T> list = new ArrayList<T>();

    if (items.length == 1 && items[0].getClass().isArray()) {
        int length = Array.getLength(items[0]);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(items[0], i);
            T item = (T)element;
            list.add(item);
        }
    } else {
        for (Object i : items) {
            T item = (T)i;
            list.add(item);
        }
    }

    return list;
}

بعد تضمينه باستخدام استيراد ثابت، يمكن أن تكون الاستخدامات المحتملة:

    long[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    List<Long> list = toList(array);

أو

    List<Long> list = toList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l);

في حين أنه من الممكن إنشاء قائمة جديدة وإضافة جميع القيم إليها (عبر حلقة أو تدفقات)، فقد كنت أعمل على صفائف كبيرة حقا واحصل على أداء ضعيف. لذلك قمت بإنشاء بلدي سهلة لاستخدام فئة المجمع صفيف بدائي.

مثال:

long[] arr = new long[] {1,2,3};
PrimativeList<Long> list = PrimativeList.create(arr); // detects long[] and returns PrimativeList<Long>

System.out.println(list.get(1)); // prints: 2
list.set(2, 15);
System.out.println(arr[2]);  // prints: 15

أحضره هنا:https://github.com/sf298/sauds-toolbox/blob/master/src/main/java/primitivearrayrapper/primitivers.java.

ملاحظة: لم أختبرها بالكامل بعد، لذلك اسمحوا لي أن أعرف إذا وجدت أي أخطاء / مشكلات.

يمكنك استخدام LongStream من أجل هذا

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top