2010-05-04 2 views
2

Хорошо, вот что я хочу сделать:Java: Как реализовать метод, который принимает 2 массива и возвращает 2 массива?

Я хочу реализовать метод кроссовера для массивов.

Предполагается взять 2 массива одинакового размера и вернуть два новых массива, которые являются разновидностью двух входных массивов. , как в [a, a, a, a] [b, b, b, b] ------> [a, a, b, b] [b, b, a, a].

Теперь интересно, какой будет предлагаемый способ сделать это на Java, поскольку я не могу вернуть более одного значения.

Мои идеи: - возврат коллекции (или массива), содержащей и новые массивы.

Мне не нравится этот, потому что, по его мнению, это приведет к сложному пониманию кода. - избегая необходимости возвращать два результата, вызывая метод для каждого случая, но каждый раз получая один из результатов.

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

Плюс, это будет работать только для этого основного корпуса, но я захочу перетасовать массив перед кроссовером и наоборот, чтобы потом. Я не могу сделать перетасовку, изолированную от кроссовера, так как я не хочу на самом деле выполнять операцию, вместо этого я хочу использовать информацию о перестановке, выполняя кроссовер, что будет более эффективным способом, я думаю.

Мой вопрос не о самом алгоритме, а о том, как поставить в в методе (относительно входа и выхода) в Java

+0

В .Net: частная пустота modifyInPlace (иая строка [] arr1, иая строка arr2) {...} В Java: Смотрите http://stackoverflow.com/questions/333151/ java-how-to-pass-byte-by-reference –

+2

Я действительно этого не понимаю. – HansDampf

+0

@ Гарниш, если он хотел изменить массивы на месте, это тоже не проблема в Java. – Yishai

ответ

11

По предложению от Брюса Eckel в книге Мышление в Java, в моих Java проектов, которые я часто включают в себя некоторые вспомогательные классы для обертывание групп из двух или трех объектов. Они тривиальны и удобны, особенно для методов, которые должны возвращать несколько объектов. Например:

public class Pair<TA,TB> { 
    public final TA a; 
    public final TB b; 

    /** 
    * factory method 
    */ 
    public static <TA,TB> Pair<TA,TB> createPair(TA a,TB b){ 
     return new Pair<TA,TB>(a,b); 
    } 

    /** 
    * private constructor - use instead factory method 
    */ 
    private Pair(final TA a, final TB b) { 
      this.a = a; 
      this.b = b; 
    } 

    public String toString() { 
     return "(" + a + ", " + b + ")"; 
    } 

} 
+0

Это хорошее предложение. Но я не уверен, что я собираюсь выбрать этот в этом случае. Вероятно, это похоже на переоценку и не поможет понять ее, потому что моя проблема довольно проста. – HansDampf

+0

Вы решаете - но я сомневаюсь, что есть что-то более чистое и ясное, чем этот подход. Обратите внимание, что класс использует generics, он не привязан к вашему конкретному варианту использования. И в вашем методе вам просто нужно сделать возврат (Pair.createPair (arr1, arr2), в конце концов. – leonbloy

+0

Я еще не решил, что, возможно, дополнительный класс не усложнит его. Как я вижу теперь вопрос о том, как решить, может быть то, что является наиболее эффективным способом. Будет ли использование «Wrapper» менее эффективным, чем использование массива напрямую. – HansDampf

3

Поскольку спецификация вашего метода является то, что он принимает два входных массивов и производит вывода, я согласен с вами в том, что метод должен возвращать оба массива одновременно.

Я думаю, что наиболее естественным выбором возвращаемого значения является int[][] длины 2 (замените int любым типом, который вы используете). Я не вижу причин, по которым он должен сделать код более сложным для понимания, особенно если вы укажете, каким будет содержимое возвращаемого значения.

Редактировать: в ответ на ваш комментарий, я понимаю, что вы это рассмотрели, и я говорю, что, несмотря на ваши стилистические возражения, я не верю, что существует строго «лучшая» альтернатива («лучше» здесь свободно определяемый в вопросе).

Альтернативный подход, в значительной степени эквивалентный этому, заключался бы в определении объекта, который обертывает два массива. Это имеет небольшое различие в возможности ссылаться на них по именам, а не по индексам массива.

+0

Хорошая идея. Насколько расточительно этот подход с точки зрения ОЗУ и ЦП? –

+0

По сравнению с чем? – danben

+0

Да, как я уже говорил, я рассматриваю этот путь. Я просто не чувствую себя комфортно с этим, поэтому я спрашиваю, есть ли у кого-то другие идеи. Причина, по которой я не чувствую себя комфортно, - это, наверное, так много, как работа, и каждый раз, используя ее, вы должны думать о том, какая запись содержит значение. – HansDampf

0

Вы строго не можете вернуть более одного значения (думаю объект или примитив) в Java. Может быть, вы можете вернуть экземпляр определенного объекта «Результат», который имеет два массива в качестве свойств?

6

Прочитайте последний раздел этой статьи:

http://www.yoda.arachsys.com/java/passing.html

процитировать:

Это реальная причина, почему пройти мимо ссылки используется во многих случаях - это позволяет чтобы эффективно иметь множество возвращаемых значений. Java не разрешает множественные «реальные» значения возврата, и это не позволяет передавать по ссылке семантику, которая будет использоваться в других языках языков с одним возвратом. Однако, вот некоторые методы для работы вокруг этого:

  1. Если какой-либо из ваших возвращаемых значений являются коды состояния, которые указывают на успех или неудачу метода, устранить их немедленно. Замените их обработкой исключений , которая выдает исключение , если метод не успешно завершен. Исключение является более стандартным способом обработки ошибок , может быть более выразительным и исключает одно из ваших возвращаемых значений .

  2. Найти связанные группы возвращаемых значений, и инкапсулировать их в объекты, которые содержат каждую часть информации в виде полой. Классы для эти объекты могут быть расширены до , а затем их последующее построение в улучшит дизайн кода . Каждый набор связанных значений , которые вы инкапсулируете в объект , удаляет возвращаемые значения из метода , увеличивая уровень абстракции интерфейса метода . Например, вместо передачи координаты X и Y со ссылкой на позволяют им быть возвращены, создать изменяемый класс Point, передать объект ссылку на значение, и обновить значения в объекта в методе.

В качестве бонуса, этот раздел был обновлен Jon тарелочкам :)

0

Вы можете передать выходные массивы в качестве параметров для метода. Это может дать вам больший контроль над распределением памяти для массивов.

0

Самый чистый и простой способ понять, как создать контейнерный компонент, содержащий два массива, и вернуть контейнер из метода. Я бы, вероятно, также передал контейнер в метод, чтобы он был симметричным.

Самый эффективный способ памяти, предполагая, что оба массива имеют одинаковую длину, заключались бы в передаче многомерного массива - Object [2] [n] - где n - длина массивов.

0

Если вы действительно против произвольного заказа, исходящего из массива 2d или коллекции, возможно, подумайте о создании внутреннего класса, который отражает логику того, что вы делаете. Вы можете просто определить класс, который содержит два массива, и вы могли бы вернуть ваш метод, с именами и функциями, которые отражают логику того, что вы делаете.

2

Лучший способ сделать это будет делать

public void doStuff(int[] array1, int[] array2) { 
    // Put code here 
} 

Поскольку Java массивы в Java передать ссылку, любые изменения, внесенные в массивы будут сделаны в самом массиве. Это имеет несколько предостережений

  1. Если вы устанавливаете его в нулевое значение необходимо использовать другой способ (например, инкапсуляции его в объект)
  2. Если вы инициализации массива (в методе), вы должны использовать другой способ

Вы могли бы использовать это в формате:

// other method 
int[] array1 = new int[20]; // the arrays can be whatever size 
int[] array2 = new int[20]; 

doStuff(array1,array2); 

// do whatever you need to with the arrays 

Edit: Это делает предположение, что это нормально, чтобы внести изменения в исходных массивах.

Если это не так, то объект (например, в ответ leonbloy определенно то, что требуется).

+2

Вы необоснованно полагаете, что это нормально, чтобы уничтожить входные массивы. – danben

+0

... но предположение, что нормально уничтожать входные массивы, может быть действительным (это не указано в вопросе). Это хорошо, если массивы большие, и преобразование все равно будет работать (экономит выделение результата). Если это не так, то массивы могут быть клонированы до перехода к методу (что приводит к компромиссу между более простой сигнатурой метода и большей работой для вызывающего). – paulcm

5

Если разумно для вызывающего абонента знать размер возвращенных массивов раньше времени, вы можете передать их в метод:

 public void foo(Object[] inOne, Object[] inTwo, Object[] outOne, Object[] outTwo) { 
      //etc. 
    } 

При этом, 90 +% от многократного возвращения времени значения из метода скрывают лучшую конструкцию. Мое решение было бы сделать преобразование внутри объекта:

 public class ArrayMixer { 
      private Object[] one; 
      private Object[] two; 
      public ArrayMixer(Object[] first, Object[] second) { 
       //Mix the arrays in the constructor and assign to one and two. 
      } 
      public Object[] getOne() { return one; } 
      public Object[] getTwo() { return two; } 
    } 

Я подозреваю, что в реальном прецеденте, что класс и массив один и массив два могут получить лучшие имена.

+0

Это освежающе хорошая идея, возможно, потому, что она лучше подходит для домена, в котором я хочу использовать метод, который я, к сожалению, забыл. Я могу представить себе класс crossoverOperator(), мне просто нужно будет попробовать проблемы с производительностью, я думаю. – HansDampf

+0

Если вы не знаете размер возвращаемых массивов, вы можете передать два пустых массива ArrayLists в качестве параметров - метод (foo) может затем соответствующим образом изменить их размер. – paulcm

0

Простым решением этой проблемы является возвращение в виде карты. Трюк этого вопроса заключается в том, как вы определяете ключи для идентификации объектов, допустим, что есть два входных массива [a, a, a, a ] [b, b, b, b] и два массива выходов [a, a, b, b] [b, b, a, a]

Для этого вы можете использовать переменную String в качестве ключа только для идентификации объектов потому что переменная String неизменна, поэтому их можно использовать в качестве ключей. И как пример

Map<String,String[]> method(String[] x,String[] y){ 

do your stuff.......... 

    Hashmap<String,String[]> map =new HashMap<String,String[]>(); 
map.put("Object2",[b,b,a,a]); 

return map; 
} 
Смежные вопросы