Как известно, в Java существует немало сфер применения коллекций и способов работы с ними. Одной же из сфер, о которых я хотел бы рассказать сегодня, является работа со сложными структурами данных.
Данный пример однажды попался мне в виде задачи и решение, которое я предложу, является не исчерпывающим, а лишь одним из возможных примеров.
Задача, стоящая в этом примере — каким-то образом организовать временное хранение некоторого количества данных из массивов, связав эти данные специфичным способом.

Данные, с которыми мы будем работать, выглядят следующим образом:

public class Transport {

public static String [][] persons {
{“Ann” “John”, “Bob” },
{“Joe”, “Donald”, “Ann”, “John”},
{“Bob”, “Ann”, “Michael”},
};

public static String [] transports {
“boat”, “car”, “bike”
};

public static void main(String [] args){

}}


В общем случае, для хранения подобных данных предпочтительно использовать отдельные классы, например, класс Person, в котором были бы описаны поля с именем или id конкретной личности и т.п…
Но бывают ситуации, когда заранее неизвестно, какого рода данные нам необходимо будет хранить, например при чтении их из xml-файла и отсутствии информации о его содержании, некоторых случаях считывания информации из базы данных и т.п. И по той или иной причине мы не можем предварительно определить полезные классы, так что одним из выходов для нас остаётся создание сложных структур данных, вроде той, что будет описана ниже.
Как видно, в примере выше представлен двумерный и одномерный массивы, первый из которых содержит имена людей, а второй – виды транспорта, которыми эти люди умеют управлять. Для простоты и наглядности данные описаны именно таким образом, указывая на то, что люди, приведённые, например, в первом подмассиве многомерного массива persons умеют управлять транспортом, описанным как нулевой элемент массива transports и т.п.
Таким образом, если нам понадобится оператор лодки (boat), мы для начала запросим человека с именем Ann, если этот человек будет недоступен – с именем John и т.п.
Как вариант, для обращения к подобным данным подошла бы коллекция типа List, например ArrayList, для того, чтобы было удобно обращаться к данным через индекс. Но т.к. у нас имеется более одного массива строк, мы будем использовать коллекцию типа Map, причем поскольку нас не интересует конкретный порядок видов транспорта, указанных в массиве transports, мы не будем использовать SortedMap:
Map<String, Set<String>>drivers;

Итак, мы определили коллекцию drivers, в которой в качестве ключа будет использоваться название конкретного вида транспорта, а в качестве значения – набор людей с уникальными именами, хранимыми, соответственно, в коллекции типа Set.
Далее необходимо определить конкретный тип Map, который мы будем использовать. Поскольку, как было сказано выше, нас не интересует порядок, в котором данные будут храниться коллекции, мы используем простейший тип — HashMap:
Map<String, Set<String>>drivers = new HashMap<String, Set<String>>();

При использовании Java 7 и выше возможно вместо этого использовать следующую конструкцию:
Map<String, Set<String>>drivers = new HashMap<>();

Следующим этапом будет итерация через массив транспортных средств transports и подборка определённого списка людей для каждого из таких транспортных средств.
for(int i = 0; i < transports.length(); i++){
String transport = transports[i];
String [] operators = persons[i];
Set <String> personsSet = new LinkedHashSet<String>();
for(String operator :  operators) {
personsSet.add(operator);
}

drivers.put(transport, personsSet);
}

Как видно из примера выше, мы пробегаем по элементам массива, содержащего названия транспортных средств, сохраняя попутно на каждой итерации наименование транспортного средства в строку transport. Она будем использована нами для добавления в коллекцию drivers в качестве ключа.
Помимо этого, на каждом этапе итерации мы также добавляем в новосозданный массив строк operators соответствующий подмассив многомерного массива опреатора транспортных средств persons.
Наконец, на каждом этапе итерации мы создаем экземпляр коллекции Set – personsSet — в виде LinkedHashSet. Как известно, Set не может содержать повторяющиеся значения, а значит он идеально подходит для хранения уникальных данных об опреаторах транспорта.
Мы используем именно этот тип Set, т.к., как было указано выше, нам не нужно хранить данные в упорядоченном виде. Вместо этого мы предпочтем хранить их в том порядке, в котором они добавляются в коллекцию.
Используя цикл foreach, мы добавляем уникальные данные в personsSet, используя значения массива operators, созданного ранее.
В конце каждого цикла for мы пополняем нашу коллекцию drivers значением transport, которое, как упоминалось выше, используется в качестве ключа, и соответствующей коллекцией personsSet в качестве значения.
В качестве совета рекомендовал бы использовать System.out.println(); на каждом этапе итерации для подтверждения того, что значения, добавляемые в соответствующие коллекции, действительно соответствуют желаемым.
Итак, наша структура создана. Теперь самое время проверить её в действии. Для этого мы создадим колллекцию типа Set и попробуем с её помощью в цикле foreach вывести значения имен людей, способных управлять определённы видом транспорта, например — автомобилем:
Set <String> people = drivers.get(“car”);
for(String carDriver : people){
System.out.println(carDriver);
} 

Так же, как вариант, можно проитерировать через весь набор значений коллекции drivers, также используя цикл foreach:
for(String trans : drivers.keySet()){
System.out.println(trans);
}

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

Комментарии (5)


  1. vedenin1980
    21.09.2015 17:51
    +2

    Опять вы учите странному…

    1) Используйте SetMultimap

    2) LinkedHashSet не нужен, достаточно HashSet

    3) превратить Array в Set: new HashSet<>(Arrays.asList( persons[i] ));

    4) и т.п.

    P.S. Желание учить радует, жалко что сначала вы не подтяните собственные знания.


    1. uvarovalexander
      21.09.2015 18:04

      Дело тут в первую очередь в том, на кого рассчитан подобный туториал. Фактически, я пишу на том уровне, на котором это некогда подавалось мне — для людей того же уровня, на котором был когда-то я. И ведь из статьи в статью я делаю на этом особый акцент в том или ином предложении. Иначе говоря, статья ориентирована на начинающий уровень — а ведь потенциальных джунов на сайте полно.
      п.с. LinkedHashSet был использован, т.к. он со 100% вероятностью сохраняет объекты в том порядке, в котором они были добавлены (а в статье написано, что это — одна из задач). в простом HashSet такой порядок очень вероятен, но не гарантирован.


  1. vedenin1980
    21.09.2015 19:26

    Иначе говоря, статья ориентирована на начинающий уровень

    Дело не в том какой уровень, даже начинающих лучше учить правильно, чтобы когда они пришли на первую работу их не приходилось долго и мучительно переучивать. Никто, конечно, не предлагает сразу давать лямбды и функциональщину, но учиться надо сразу тому как написать пусть очень небольшой кусочек кода, но так чтобы перед team lead'ом не было мучительно стыдно.

    я пишу на том уровне, на котором это некогда подавалось мне

    К сожалению, «уровни» придумали в наших институтах чтобы оправдать почему они учат не очень правильно (так как практикующих хороших программистов в ВУЗах мало), в западных вузах сразу учат по реальным практическим примерам, так чтобы студентов не пришлось мучительно переучивать code style'у на первой работе.


  1. agent10
    21.09.2015 20:07

    Думаю надо указать в начале, что статья для начинающих. Целую статью ожидал, что вот-вот будет мощнейший Java хак… но нет… просто структура в структуре)


  1. nomit
    21.09.2015 20:16

    Немного в шоке от статьи, думал тут чтиво будет наитереснейшее(повелся на название статьи), а получил не знаю даже как описать :(