Helpers - компьютеры, интернет, программирование

Группировать сообщения из файла json по идентификатору пользователя

Я могу прочитать файл JSON, содержащий список сообщений и их соответствующих авторов. Структура одного сообщения следующая:

JSON

{
"created_at": "Thu Apr 30 10:47:49 +0000 2015",
"id": 593728455901990900,
"user": {
    "id": 12,
    "name": "GiGi",
    "user_date": "Thu May 17 10:47:49 +0000 2010"
}

}

Классы Author и Message (POJO) содержат поля, которые мы хотим проанализировать, и функцию toString(), которая отображает поля в виде строки.

Автор

public class Author {

    @SerializedName("id")
    private static long id;

    @SerializedName("created_at")
    private static String user_date;

    private static String name;

    public  String toString() {
        return name + "\n" + id + "\n" + user_date;         
    }
    ....Getters & Setters....
}

Сообщение

public class Message {

    @SerializedName("user")
    Author author;   

    @SerializedName("created_at")
    String date;

    long id;

    public String toString() {
        return id + "\n" + date;        
    }

}

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

ОБНОВЛЕНИЕ

Решением было бы создать Карту, которая имеет одно из свойств автора как KEY (в этом образце кода это идентификатор автора) и соответствующий список сообщений как VALUE.

Map<Long, List<Message>> map = new HashMap<Long, List<Message>>();
for (Message msg : listOfMessages) {      
    long key = msg.getAuthor().getId();

    if (map.get(key) == null) {
        map.put(key, new ArrayList<Message>());
    }
    map.get(key).add(msg);
}

ВОПРОСЫ, которые могут возникнуть из этого решения:

  • Как можно отобразить id И имя автора и соответствующий им список сообщений?
  • Я не совсем уверен в элегантности этого решения, так как класс Message содержит класс Author и много ненужной информации «переносится» внутри значений MAP.

РЕШЕНИЕ

После добавления методов equals и hashCode в класс Author мы можем отображать экземпляры Author как ключи.

@Override
public int hashCode() {
    int hash = 7;
    hash = 23 * hash + (int) (this.id ^ (this.id >>> 32));
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Author author = (Author) obj;
    if (this.id != author.id) {
        return false;
    }
    return true;
}

А в основном классе мы можем пройтись по списку сообщений и правильно заполнить карту:

Map<Author, List<Message>> map = new HashMap<Author, List<Message>>();
for (Message message : listOfMessages) {
    List<Message> userMessages = map.get(message.getAuthor());
    if (userMessages == null) {
        userMessages = new ArrayList<Message>();
        map.put(message.getAuthor(), userMessages);
    }
    userMessages.add(message);
}
for (Entry<Author, List<Message>> entry : map.entrySet()) {
    System.out.println(entry.getKey().getId());
    for (Message message : entry.getValue()) {
        System.out.println("\t" + message.getDate());
    }
}

ВЫВОД

3037057186
    Thu Apr 30 10:47:52 +0000 2015
1598532858
    Thu Apr 30 10:47:51 +0000 2015
67267979
    Thu Apr 30 11:47:49 +0000 2015
    Thu Apr 30 10:47:49 +0000 2015
    Thu Apr 30 10:47:49 +0000 2015
    Thu Apr 30 10:47:49 +0000 2015
06.05.2015

  • display the messages grouped by user? Логин пользователя? 06.05.2015

Ответы:


1

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

   "created_at":"Thu Apr 30 10:47:49 +0000 2015",
   "id":593728455901990912,
   "user":{  
      "id":12,
      "name":"GiGi",
      "user_date":"Thu May 17 10:47:49 +0000 2010",
   }

to

{
    "created_at": "Thu Apr 30 10:47:49 +0000 2015",
    "id": 593728455901990900,
    "user": {
        "id": 12,
        "name": "GiGi",
        "user_date": "Thu May 17 10:47:49 +0000 2010"
    }
}

Вам также необходимо добавить геттеры и сеттеры в класс Author и сделать свойства нестатическими, чтобы свойства устанавливались парсером, в данном случае GSON.

Тогда это просто вопрос группировки сообщений по пользователю:

        Map<Long, List<Message>> userGroup = new HashMap<>();
        for (Message message : messages) {
            List<Message> userMessages = userGroup.get(message.author.getId());
            if (userMessages == null) {
                userMessages = new ArrayList<>();
                userGroup.put(message.author.getId(), userMessages);
            }
            userMessages.add(message);
        }
        for (Entry<Long, List<Message>> entry : userGroup.entrySet()) {
            for (Message message : entry.getValue()) {
                System.out.println(entry.getKey() + " : " + message.date);
            }
        }

ОБНОВЛЕНИЕ

Вы можете использовать ключ Author, добавив методы equals и hashCode в класс Author. Что-то вроде этого:

@Override
public int hashCode() {
    int hash = 7;
    hash = 23 * hash + (int) (this.id ^ (this.id >>> 32));
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Author other = (Author) obj;
    if (this.id != other.id) {
        return false;
    }
    return true;
}

Таким образом, вы можете группировать по Author вместо Long

Map<Author, List<Message>> userGroup = new HashMap<>();
for (Message message : messages) {
    List<Message> userMessages = userGroup.get(message.author);
    if (userMessages == null) {
        userMessages = new ArrayList<>();
        userGroup.put(message.author, userMessages);
    }
    userMessages.add(message);
}
for (Entry<Author, List<Message>> entry : userGroup.entrySet()) {
    System.out.println(entry.getKey().getId());
    for (Message message : entry.getValue()) {
        System.out.println("\t" + message.date);
    }
}
07.05.2015
  • Да, это почти правильно. Таким образом, у меня есть карта с идентификатором автора в качестве ключа и списком сообщений в качестве значения, но что, если я хочу отобразить имя и идентификатор автора вместе со списком соответствующих сообщений? 07.05.2015
  • Просто используйте автора из первого сообщения в списке или, в зависимости от того, что вы хотите сделать, просто получайте его из каждого сообщения, когда вы перебираете их. Другой способ — добавить метод equals и hash в класс Author и использовать его в качестве ключа на карте. 08.05.2015

  • 2

    Рассмотрим этот файл json example.json

     [
        { 
         "date":"Thu Apr 30 10:47:49 +0000 2015",
         "id":593728455901990912,
         "author":{  
               "id":12,
                "name":"GiGi",
                "user_date":"Thu May 17 10:47:49 +0000 2010"
                } 
        },
    
        { 
         "date":"Thu Apr 30 10:47:49 +0000 2013",
         "id":593728455901990977,
         "author":{  
               "id":12,
                "name":"GiGi",
                "user_date":"Thu May 17 10:47:49 +0000 2010"
                } 
        },
    
        {
          "date":"Thu Apr 30 10:47:49 +0000 2015",
          "id":593728422901330999,
          "author":{  
                "id":13,
                 "name":"HiHi",
                 "user_date":"Thu May 17 10:47:49 +0000 2015"
                  }
        }
     ]
    

    Авторский класс

    class Author {    
        private long id;
        private String name;
        private String user_date;
        public String toString() {
            return name + " " + id + " " + user_date;
        }    
       //getters, setters,...   
    }
    

    Класс сообщения

    class Message {
        String date;
        long id;
        Author author;
        public String toString() {
            return id + " " + date;
        }
       //getters, setters,...
    }
    

    Разбор json с помощью Gson API

    Gson gson = new Gson();
    List<Message> list = gson.fromJson(new BufferedReader(new FileReader(
                "example.json")), new TypeToken<List<Message>>() {
    }.getType());
    

    Отображать сообщения, сгруппированные по идентификатору пользователя

    Map<Long, List<Message>> groupedMap = list.stream().collect(
                Collectors.groupingBy(m->  m.getAuthor().getId()));
    
    groupedMap.forEach((k, v) -> System.out.println(k + " => " + v));
    

    Вывод:

    12 => [593728455901990912 Thu Apr 30 10:47:49 +0000 2015, 593728455901990977 Thu Apr 30 10:47:49 +0000 2013]
    13 => [593728422901330999 Thu Apr 30 10:47:49 +0000 2015]
    
    06.05.2015
  • К сожалению, формат файла json немного отличается, так как я получаю ответы json от потокового API. Я мог преодолеть это, переформатировав файл. Коллекторы из Java 8 — хорошее решение, но оно дает мне исключение NPE, а также я бы предпочел, чтобы решение было основано на Java 7. 07.05.2015

  • 3

    используйте Джексона, это даст вам возможность сопоставить json с объектом POJO с помощью аннотации.

    06.05.2015
  • Я могу разобрать json (используя библиотеку GSON), но я не могу отображать сообщения, сгруппированные пользователем 06.05.2015
  • сделайте так, чтобы ваше сообщение расширяло хэш-карту и переопределяло метод put, в этом случае вы можете прочитать пользователя и добавить его в хэш-карту 06.05.2015
  • Когда Message расширяет HashMap, в этот момент возникает исключение: Message message = gson.fromJson(jsonmessage, Message.class); › java.lang.IllegalStateException: Ожидалась строка, но BEGIN_OBJECT 07.05.2015
  • Новые материалы

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

    Использование машинного обучения для диагностики болезни Альцгеймера, часть 4
    Маркеры семантической согласованности для ранней диагностики болезни Альцгеймера (arXiv) Автор: Давиде Колла , Маттео Дельсанто , Марко Агосто , Бенедетто Витиелло , Даниэле Паоло Радичони..

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

    Анимированный математический анализ
    Использование Manim для создания математических анимированных визуализаций Визуализация данных помогает понять скрытые закономерности в данных, которые невозможно визуализировать..

    Создание простого слайдера изображений с помощью JavaScript
    Узнайте, как создать базовый слайдер изображений с помощью HTML, CSS и JavaScript. Введение В этом уроке мы создадим удобный слайдер изображений, используя JavaScript, HTML и CSS. Ползунок..

    Создание базы данных с помощью супергероя «Python»
    В этом посте мы узнаем, как создать «базу данных SQLite с помощью модуля python sqlite3, создав простую функцию входа и регистрации. Готовы ли вы к этому путешествию? Если да , давайте приступим..

    ИИ для чайников: руководство для начинающих по пониманию будущего технологий
    Вы чувствуете, что остались позади в мире ИИ? Не волнуйтесь, вы не одиноки! Со всей этой шумихой вокруг искусственного интеллекта может быть трудно понять, с чего начать. Но не позволяйте сленгу..