Як перетворити int [] в Integer [] на Java?


167

Я новачок у Java і дуже розгублений.

У мене великий набір даних довжиною 4, int[]і я хочу підрахувати кількість разів, коли кожна конкретна комбінація з 4 цілих чисел відбувається. Це дуже схоже на підрахунок частот слова в документі.

Я хочу створити, Map<int[], double>що відображає кожен int [] на кількість показів, оскільки список повторюється, але Map не приймає примітивні типи.

тому я зробив Map<Integer[], Double>

мої дані зберігаються як ArrayList<int[]>мій цикл

ArrayList<int[]> data = ... // load a dataset`

Map<Integer[], Double> frequencies = new HashMap<Integer[], Double>();

for(int[] q : data) {

    // **DO SOMETHING TO convert q from int[] to Integer[] so I can put it in the map

    if(frequencies.containsKey(q)) {
    frequencies.put(q, tfs.get(q) + p);
    } else {
        frequencies.put(q, p);
    }
}

Я не впевнений, який код мені потрібен у коментарі, щоб зробити цю роботу для перетворення int[]в Integer[]. А може, я принципово розгублений щодо правильного способу цього зробити.


6
"Я хочу створити Map <int [], double> ... але Map не приймає примітивних типів." Як зазначалося в одній із публікацій нижче, int [] не є примітивним типом, тому це не справжня проблема. Справжня проблема полягає в тому, що масиви не замінюють .equals () для порівняння елементів. У цьому сенсі перетворення на Integer [] (як висловлюється у вашій назві) не допоможе вам. У наведеному вище коді частота.containsKey (q) все одно не буде працювати, як ви очікували, оскільки для порівняння використовує .equals (). Справжнє рішення - не використовувати тут масиви.
newacct

Не хочете спамувати з іншою відповіддю, але варто зазначити, що зараз є приклад документації щодо цього.
Мурейник

Відповіді:


189

Рідна Java 8 (один рядок)

З Java 8 int[]можна легко перетворити Integer[]:

int[] data = {1,2,3,4,5,6,7,8,9,10};

// To boxed array
Integer[] what = Arrays.stream( data ).boxed().toArray( Integer[]::new );
Integer[] ever = IntStream.of( data ).boxed().toArray( Integer[]::new );

// To boxed list
List<Integer> you  = Arrays.stream( data ).boxed().collect( Collectors.toList() );
List<Integer> like = IntStream.of( data ).boxed().collect( Collectors.toList() );

Як зазначали інші, Integer[]це, як правило, не хороший ключ картки. Але що стосується конверсії, то зараз у нас є відносно чистий і рідний код.


3
Це тим часом правильний шлях. Якщо вам потрібен масив Integer-Array як список, ви можете написати:List<Integer> list = IntStream.of(q).boxed().collect(Collectors.toList());
aw-think

для перетворення в Integer[]I, я б фактично запропонував використовувати наступний синтаксис: Integer[] boxed = IntStream.of(unboxed).boxed().toArray();Аналогічно, як @NwDx
YoYo

1
@JoD. Так, це працює. Але IntStream.ofдзвонить Arrays.streamвсе одно. Я думаю, що це зводиться до особистих переваг - я віддаю перевагу одній переоціненій функції, а деякі люблять використовувати більш чіткий клас.
Sheepy

2
Це божевільне, але чудове рішення! Дякую!
Ругал

1
@VijayChavda Новий синтаксис, який називається посиланнями на метод , був представлений у 2014 році з Java 8 як частина лямбда ( JSR 335, частина C ). Це означає the "new" method (constructor) of the Integer[] class.
Sheepy

79

Якщо ви хочете перетворити int[]на Integer[], не існує автоматизованого способу зробити це в JDK. Однак ви можете зробити щось подібне:

int[] oldArray;

... // Here you would assign and fill oldArray

Integer[] newArray = new Integer[oldArray.length];
int i = 0;
for (int value : oldArray) {
    newArray[i++] = Integer.valueOf(value);
}

Якщо у вас є доступ до бібліотеки язика Apache , ви можете скористатися таким ArrayUtils.toObject(int[])методом:

Integer[] newArray = ArrayUtils.toObject(oldArray);

71
це неприємний спосіб зробити цикл.
Джеймс Беквар

9
Це абсолютно нормально для кожного ... Я не бачу противної частини.
Дахака

18
@Dahaka, гнучкість полягає у використанні ітератора часу, в valueтой час iяк там є змінна індексування .
lcn

1
@Icn, я можу зрозуміти, чому деякі люди не віддають перевагу такому стилю, але що робить його настільки небажаним, щоб бути бридким?
Едді

14
@icn, @Dahaka: Гнучкість полягає в тому, що оскільки ви вже використовуєте змінну індексу збільшення, немає необхідності використовувати і для кожного; Хоча це виглядає досить просто і просто в коді, за кадром, що передбачає зайві накладні витрати. Традиційний for (int i...)цикл був би тут більш ефективним.
дайског

8

Імовірно, ви хочете, щоб ключ на карті відповідав значенню елементів замість ідентичності масиву. У цьому випадку ви хочете якийсь об'єкт, який визначаєequals і hashCodeяк ви очікували. Найпростіше це перетворити на List<Integer>, ArrayListабо краще використання Arrays.asList. Краще, ніж ви можете ввести клас, який представляє дані (подібний до, java.awt.Rectangleале я рекомендую зробити змінні приватними остаточними, і клас остаточним).


О, ось питання про перетворення масиву, навпаки: stackoverflow.com/questions/564392/…
Том Хоутін - Tackline

8

Використання звичайного циклу for-циклу без зовнішніх бібліотек:

Перетворити int [] в Integer []:

int[] primitiveArray = {1, 2, 3, 4, 5};
Integer[] objectArray = new Integer[primitiveArray.length];

for(int ctr = 0; ctr < primitiveArray.length; ctr++) {
    objectArray[ctr] = Integer.valueOf(primitiveArray[ctr]); // returns Integer value
}

Перетворити Integer [] в int []:

Integer[] objectArray = {1, 2, 3, 4, 5};
int[] primitiveArray = new int[objectArray.length];

for(int ctr = 0; ctr < objectArray.length; ctr++) {
    primitiveArray[ctr] = objectArray[ctr].intValue(); // returns int value
}

6

Я помилявся в попередній відповіді. Правильним рішенням є використання цього класу як ключа в карті, що загортає фактичний int [].

public class IntArrayWrapper {
        int[] data;

        public IntArrayWrapper(int[] data) {
            this.data = data;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            IntArrayWrapper that = (IntArrayWrapper) o;

            if (!Arrays.equals(data, that.data)) return false;

            return true;
        }

        @Override
        public int hashCode() {
            return data != null ? Arrays.hashCode(data) : 0;
        }
    }

і змінити код так:

   Map<IntArrayWrapper, Double > freqs = new HashMap<IntArrayWrapper, Double>();

    for (int[] data : datas) {
        IntArrayWrapper wrapper = new IntArrayWrapper(data);

        if ( freqs.containsKey(wrapper)) {
            freqs.put(wrapper, freqs.get(wrapper) + p);
        }

        freqs.put(wrapper, p);
    }

1
Я зробив би клас заключним, а поле приватним фіналом. Зробіть захисну копію масиву в конструкторі (клоні). І просто поверніть значення з Arrays.equals, а не маєте те своєрідне оператор if. toString було б добре.
Том Хотін - тайклін

1
Ой і кинь NPE від конструктора (ймовірно, викликує клону) для нульових даних, а не маєш реєстрації в hashCode.
Том Хотін - тайклін

Щоправда .. Але код для рівних, hashCode генерується IDEA :-). Працює правильно.
Mihai Toader

6
  1. Перетворити int [] в Integer []

    public static Integer[] toConvertInteger(int[] ids) {
    
      Integer[] newArray = new Integer[ids.length];
         for (int i = 0; i < ids.length; i++) {
           newArray[i] = Integer.valueOf(ids[i]);
         }
       return newArray;
    }
  2. Перетворити Integer [] в int []

    public static int[] toint(Integer[] WrapperArray) {
    
       int[] newArray = new int[WrapperArray.length];
          for (int i = 0; i < WrapperArray.length; i++) {
             newArray[i] = WrapperArray[i].intValue();
          }
       return newArray;
    }

2
Це досить неточно через автобокс. У 1-му прикладі ви можете просто зробити, newArray[i] = ids[i];а у другому newArray[i] = WrapperArray[i]:)
Вугор Лі

3

Замість того, щоб написати свій власний код, ви можете використовувати IntBuffer, щоб обернути існуючий int [], не потребуючи копіювання даних у масив Integer

int[] a = {1,2,3,4};
IntBuffer b = IntBuffer.wrap(a);

IntBuffer реалізує порівнянні, так що ви можете використовувати вже написаний код. Формально карти порівнюють ключі таким чином, що a.equals (b) використовується, щоб сказати, що два ключі рівні, тому два IntBuffers з масивом 1,2,3 - навіть якщо масиви знаходяться в різних місцях пам'яті - кажуть, що вони рівні і тому буде працювати над своїм частотним кодом.

ArrayList<int[]> data = ... // load a dataset`

Map<IntBuffer, Double> frequencies = new HashMap<IntBuffer, Double>();

for(int[] a : data) {

    IntBuffer q = IntBuffer.wrap(a);

    if(frequencies.containsKey(q)) {
        frequencies.put(q, tfs.get(q) + p);
    } else {
        frequencies.put(q, p);
    }

}

Сподіваюся, що це допомагає


2

Не знаєте, навіщо вам потрібен подвійний на вашій карті. Що стосується того, що ви намагаєтеся зробити, у вас є int [], і ви просто хочете рахувати, скільки разів відбувається кожна послідовність? Навіщо для цього потрібен подвійний?

Що б я зробив, це створити обгортку для масиву int з належними методами .equals та .hashCode, щоб врахувати той факт, що сам об'єкт int [] не враховує дані у своїй версії цих методів.

public class IntArrayWrapper {
    private int values[];

    public IntArrayWrapper(int[] values) {
        super();
        this.values = values;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(values);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IntArrayWrapper other = (IntArrayWrapper) obj;
        if (!Arrays.equals(values, other.values))
            return false;
        return true;
    }

}

А потім скористайтеся мультисетом google guava, який призначений саме для підрахунку випадкових дій, якщо тип елемента, який ви вводите в нього, має належні методи .equals та .hashCode.

List<int[]> list = ...;
HashMultiset<IntArrayWrapper> multiset = HashMultiset.create();
for (int values[] : list) {
    multiset.add(new IntArrayWrapper(values));
}

Потім, щоб отримати рахунок для будь-якої конкретної комбінації:

int cnt = multiset.count(new IntArrayWrapper(new int[] { 0, 1, 2, 3 }));

Це, IntArrayWrapperбезумовно, є правильним підходом до використання int[]масиву як хеш-ключа, але слід зазначити, що такий тип вже існує ... Ви можете використовувати його, щоб обернути масив, і він не тільки має його, hashCodeа equalsце навіть порівняно.
Холгер

2

Оновлення. Хоча компілюється нижче, це призводить до ArrayStoreExceptionвиконання. Дуже погано. Я нехай це залишиться для подальшого ознайомлення.


Перетворення в int[], до Integer[]:

int[] old;
...
Integer[] arr = new Integer[old.length];
System.arraycopy(old, 0, arr, 0, old.length);

Я мушу визнати, що я трохи здивований, що це компіляція, враховуючи System.arraycopyнизький рівень і все, але це так. Принаймні в java7.

Ви можете конвертувати інший спосіб так само легко.


2
Я не бачу великої цінності в тому, щоб відповісти на цю відповідь "для довідок", коли вона не працює. У документації для System.arraycopy () навіть зазначено, що вона не працюватиме з цією метою.
Zero3

2

Це спрацювало як шарм!

int[] mInt = new int[10];
Integer[] mInteger = new Integer[mInt.length];

List<Integer> wrapper = new AbstractList<Integer>() {
    @Override
    public int size() {
        return mInt.length;
    }

    @Override
    public Integer get(int i) {
        return mInt[i];
    }
};

wrapper.toArray(mInteger);

Привіт Тунакі, чи можете ви мені пояснити наведений вище код? коли я пробіжу через налагоджувач, я бачу, що метод отримання та розміру викликається автоматично, тобто з викликом їх чітко !! як так?! чи можете ви поясніть, будь ласка?
forkdbloke

0

Перетворити int [] в Integer []:

    import java.util.Arrays;
    ...

    int[] aint = {1,2,3,4,5,6,7,8,9,10};
    Integer[] aInt = new Integer[aint.length];

    Arrays.setAll(aInt, i -> aint[i]);

-1

вам не потрібно. int[]є об'єктом і може використовуватися як ключ всередині карти.

Map<int[], Double> frequencies = new HashMap<int[], Double>();

- це правильне визначення карти частот.

Це було неправильно :-). Правильне рішення також розміщено :-).


Велике спасибі за вашу відповідь, я спробував це спочатку, і він склався чудово, але, схоже frequencies.containsKey(q), завжди було б помилковим, навіть якщо я маю putтой самий масив двічі - чи є тут якийсь глюк, що передбачає визначення яви рівності з int [] 's?

1
(Підказка, (new int [0]). Equals (new int [0]) - false; (новий ArrayList <Integer> ()). Дорівнює (новий ArrayList <String> ()) вірно.
Том Хоутін - таклін

1
Погана ідея, оскільки порівняння масиву ґрунтується на еталонній рівності. Ось чому Arrays.equals () існує ...
sleske

Чорт :-). Я сподівався, що я маю рацію. Декларація правильна, але семантика помилкова через те, що рівноправна рівноправна річ.
Mihai Toader

-3

Просто використовуйте:

public static int[] intArrayToIntegerArray(int[] a) {
    Integer[] b = new Integer[a.length];
    for(int i = 0; i < array.length; i++){
        b[i] = a[i];
    }
    return g;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.