Каков наилучший способ получить результат с помощью функции Java8? - PullRequest
2 голосов
/ 31 мая 2019

Мне нужно отфильтровать элементы, а затем отсортировать по определенному столбцу.Пост, что мне нужно будет найти уникальные записи, основанные на комбинации столбцов.Поскольку это обработка файла, для обозначения значения столбца в качестве разделителя используется труба (|).

String s1= "12|Thor|Asgaurd|1000000|Avenger|Active"
String s2= "234|Iron man|New York|9999999|Avenger|Active"
String s3= "420|Loki|Asgaurd|||Inactive"
String s4= "12|Thor|Asgaurd Bank|1000000|Avenger HQ|Active"

Сначала необходимо отфильтровать данные на основе состояния «Активный / Неактивный».Затем его нужно отсортировать по 4-му столбцу.Наконец, уникальность должна поддерживаться путем объединения столбца 1,2,3.

Ожидаемый результат =

"234|Iron man|New York|9999999|Avenger|Active"
"12|Thor|Asgaurd|1000000|Avenger|Active"

Ответы [ 4 ]

1 голос
/ 31 мая 2019

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

import java.util.Comparator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

List<String> result = Stream.of(s1, s2, s3, s4)
            .filter(s -> s.split("\\|")[5].equals("Active"))
            .sorted(Comparator.comparing(e -> e.split("\\|")[4]))
            .collect(Collectors.toList());
0 голосов
/ 31 мая 2019

Прежде всего вы должны создать объект, который представляет ваши данные String. Примерно так:

public class MyObject {
    private int id;
    private String name;
    private String location;
    private Integer value;
    private String category;
    private String state;

    public MyObject(String entry) {
        String[] parts = entry.split("\\|");
        if (parts.length != 6) {
            throw new IllegalArgumentException("entry has not 6 parts");
        }
        id = Integer.parseInt(parts[0]);
        name = parts[1];
        location = parts[2];
        try {
            value = Integer.parseInt(parts[3]);
        } catch (NumberFormatException ignored) {
        }
        category = parts[4];
        state = parts[5];
    }

    // getters

    @Override
    public String toString() {
        return String.join("|", String.valueOf(id), name, location, String.valueOf(value), category, state);
    }
}

С этим вы можете создать поток объектов из ваших строк и фильтра, затем выполнить сортировку и различные операции:

Collection<MyObject> result = Stream.of(s1, s2, s3, s4)
        .map(MyObject::new)
        .filter(o -> "Active".equals(o.getState()))
        .sorted(Comparator.comparing(MyObject::getValue).reversed())
        .collect(Collectors.toMap(o -> Arrays.asList(o.getId(), o.getName()), 
                Function.identity(), (o1, o2) -> o1, LinkedHashMap::new))
        .values();

result.forEach(System.out::println);

После операции карты вы фильтруете значения по состоянию и сортируете их по столбцу 4 (value в моем случае). В конце вы собираете все значения в карте для отдельной операции. Добавьте все значения, для которых вы хотите различить, в Arrays.asList(). В качестве значений карта принимает все исходные значения (Function.identity()). Для дубликатов мы сохраняем первое значение ((o1, o2) -> o1) и используем LinkedHashMap для сохранения порядка элементов. В конце мы используем только значения карты.

Если вам нужен List вместо Collection, используйте new ArrayList(result).

Результат будет таким:

234|Iron man|New York|9999999|Avenger|Active
12|Thor|Asgaurd|1000000|Avenger|Active
0 голосов
/ 31 мая 2019

Вы можете решить свою задачу следующим образом:

Во-первых, просто создайте POJO (Plain Old Java Object) и переопределите метод toString().

class MarvelPerson {

    private Integer id;
    private String name;
    private String origin;
    private Integer point = null;
    private String faction;
    private String status;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
    }

    public Integer getPoint() {
        return point;
    }

    public void setPoint(Integer point) {
        this.point = point;
    }

    public String getFaction() {
        return faction;
    }

    public void setFaction(String faction) {
        this.faction = faction;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(id);
        builder.append("|");
        builder.append(name);
        builder.append("|");
        builder.append(origin);
        builder.append("|");
        if(point != null) {
            builder.append(point);
        }
        builder.append("|");
        if(faction != null) {
            builder.append(faction);
        }
        builder.append("|");
        builder.append(status);

        return builder.toString();
    }
}

Затем вы должны написать парсер из строки в MarvelPerson. Примечание: осторожно, моя реализация довольно проста, и я полагаю, что она должна быть изменена, потому что я, возможно, не предвидел некоторые угловые случаи.

class PersonParser {

    static MarvelPerson parse(String data) {
        MarvelPerson person = new MarvelPerson();

        String[] array = data.split("\\|", -1);

        person.setId(Integer.parseInt(array[0]));
        person.setName(array[1]);
        person.setOrigin(array[2]);

        if(!array[3].isEmpty()) {
            person.setPoint(Integer.parseInt(array[3]));
        }

        if(!array[4].isEmpty()) {
            person.setFaction(array[4]);
        }

        person.setStatus(array[5]);

        return person;
    }

}

А потом ваше решение:

public class Test {

    public static void main(String[] args) {
        List<MarvelPerson> list = new ArrayList<>();

        list.add(PersonParser.parse("12|Thor|Asgaurd|1000000|Avenger|Active"));
        list.add(PersonParser.parse("234|Iron man|New York|9999999|Avenger|Active"));
        list.add(PersonParser.parse("420|Loki|Asgaurd|||Inactive"));
        list.add(PersonParser.parse("12|Thor|Asgaurd Bank|1000000|Avenger HQ|Actie"));

        list.stream()
                .filter(marvelPerson -> marvelPerson.getStatus().equals("Active"))
                .sorted((o1, o2) -> o1.getPoint() <= o2.getPoint() ? 1 : -1)
                .forEach(marvelPerson -> {
                    System.out.println(marvelPerson.toString());
                });
    }

}

Вывод на печать:

234 | Железный человек | Нью-Йорк | 9999999 | Мститель | Актив 12 | Тор | Asgaurd | +1000000 | Avenger | Активный

0 голосов
/ 31 мая 2019

Кажется, что вы не можете фильтровать, пока все только в строке. Попробуйте это,

создайте новый класс модели, который может содержать ваши столбцы. Пример:

class MyData{
 private String name;
 private String city;
 private String distance;
 private String organization;
 private String status;
 //And create Getter Setter method for all above fields.
}

Теперь пришли к вашему основному классу, где вы можете поиграть со своим кодом.

Map<MyData> map = new HashMap<MyData>();
 MyData myData = new MyData();
 myData.setName("Thor");
 myData.setCity("Asgaurd");
 myData.setDistance("1000000");
 myData.setOrganization("Avenger");
 myData.setStatus("Active");
 map.put(12, myData);
//Same thing for all other data (note: use the loop for data insertion in map)

Map<String, MyData> sorted = map.entrySet().stream().sorted(comparingByValue()).collect(toMap(e -> e.getKey(), e -> e.getValue().getName(), (e1, e2) -> e2,LinkedHashMap::new));

System.out.println("map after sorting by values: " + sorted);
...