2016-03-14 2 views
1

Я ищу элегантный способ преобразования List<List<float[]>> в float[] путем сглаживания. Я думал, что это будет легкий ветерок, но, видимо, я ошибся. Я не могу использовать Java 8 или внешние библиотеки для решения проблемы. Я также не знаю размеров внутренних списков и массивов, и они не обязательно имеют одинаковый размер.Список Список массивов поплавков массиву float в Java

Это то, что у меня есть, я думаю, что это слишком сложно для такой простой задачи:

private float[] toFloatBuffer(List<List<float[]>> buffers) { 
    //First: creating a new list to store the Float values 
    List<Float> mergedList = new ArrayList<>(); 
    //Adding the float values to the mergedList 
    for(List<float[]> secondBuffer : buffers) { 
     for(float[] b : secondBuffer) { 
      for(float f : b) { 
       mergedList.add(f); 
      } 
     } 
    } 
    //Creating the final buffer with the size of mergedList 
    float[] merged = new float[mergedList.size()]; 
    //This doesn't work for some odd reason... 
    //float[] merged = mergedList.toArray(); 
    int i = 0; 
    //Adding the values of mergedList to merged 
    for(float f : mergedList) { 
     merged[i++] = f; 
    } 
    return merged; 
} 

Edit: Я забыл сказать, что внешний список является LinkedList для некоторых хороших причин. Может быть, это важно знать.

+0

Это немного сложный и неэффективный. Однако вы не можете значительно уменьшить сложность, в которой должен быть установлен вложенный цикл 'for'. Вы в значительной степени это получили. – markspace

+0

Жаль, я думаю, что это самый уродливый код, который я написал в этом году ... – wardva

ответ

3

Вот как бы я это сделал, хотя я не уверен, что это красивее, он должен быть более эффективным esp, поскольку он не создает никаких объектов Float.

public static float[] flatten(List<List<float[]>> lists) { 
    // get the total size. 
    int size = 0; 
    for (List<float[]> list : lists) 
     for (float[] floats : list) 
      size += floats.length; 
    // create an array of the right size. 
    float[] ret = new float[size]; 
    int i = 0; 
    for (List<float[]> list : lists) 
     for (float[] floats : list) { 
      // bulk copy the array 
      System.arraycopy(floats, 0, ret, i, floats.length); 
      i += floats.length; 
     } 
    return ret; 
} 

Это создает некоторые итераторы, однако Escape Analysis может помещать их в стек, чтобы избежать мусора.

Следующая создает только один объект

public static float[] flatten(List<List<float[]>> lists) { 
    int size = 0; 
    for (int i = 0; i < lists.size(); i++) { 
     List<float[]> list = lists.get(i); 
     for (int j = 0; j < list.size(); j++) { 
      float[] floats = list.get(j); 
      size += floats.length; 
     } 
    } 
    float[] ret = new float[size]; 
    int pos = 0; 
    for (int i = 0; i < lists.size(); i++) { 
     List<float[]> list = lists.get(i); 
     for (int j = 0; j < list.size(); j++) { 
      float[] floats = list.get(j); 
      System.arraycopy(floats, 0, ret, pos, floats.length); 
      pos += floats.length; 
     } 
    } 
    return ret; 
} 

Если вы создаете List<Float> создать хотя бы один объект для каждого элемента.

+1

Второй пример Питера - это то, о чем я думал. Иногда уродливый код является правильным кодом. – markspace

+0

Спасибо, это выглядит уже лучше, чем моя реализация. Честно говоря, я проиграл вам часть анализа Escape. Можете ли вы дать мне краткое объяснение, почему второй пример лучше первого? – wardva

+1

Обратите внимание, что позднее OP добавил, что «внешний список является LinkedList по некоторым веским причинам», поэтому, вероятно, неразумно использовать индексированный доступ к нему. Я сомневаюсь, что причины LinkedList хороши, но это другое обсуждение. :-) –

0

Пожалуйста, смотрите этот элегантный рекурсивный пример, который вы можете приспособиться к вашей потребности:

https://gist.github.com/l-ray/11472207

Как и с любым рекурсивным алгоритмом, вы должны добавить некоторые проверки, чтобы избежать переполнения, если ваши списки огромны.

Смежные вопросы