Объединить значения списка данных, которые почти равны - PullRequest
0 голосов
/ 22 февраля 2019

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

это что-то вроде конфигуратора.данные, которые я получаю, выглядят примерно так:

123: 45: AB = 12 Это означает: если вариант 1 равен 1 или 2 или 3, а вариант 2 равен 4 или 5, а вариант 3 равен A или B, результатбудет 1 И 2 ​​

Я создал класс, который выглядит примерно так:

Class Options{
    String opt1;
    String opt2;
    String opt3;
    String optResult;

    //and some other stuff

    boolean hasSameOptions(Options o){
        return opt1.equals(o.opt1) && opt2.equals(o.opt2) && opt3.equals(o.opt3);
    }

    public void AddOptions(String options) {
        for (String s : options.split("")) {
            if (!optResult.contains(s)) {
                optResult = optResult + s;
            }
        }
    }

}

Теперь данные повторяются и могут быть объединены.Например:

12 : 45 : AB = 12
12 : 45 : AB = 3
12 : 45 : AB = 4

Это на самом деле означает: 12: 45: AB = 1234

Итак, я делаю строки на части, чтобы получить только отдельные значения с результатом, дляпример:

1 : 4 : A = 12
1 : 4 : B = 12
1 : 5 : A = 12 
//and so on.

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

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

public static List<Options> cleanList(List<Options> oldList) {

    List<Options> newList = new ArrayList<>();
    for (Options item : oldList) {
        Options temp = findEqualOptions(newList, item);
        if (temp != null)
            temp.AddOptions(item.optResult);
        else
            newList.add(item);
    }

    return newList;
}

public static <T> T findByProperty(Collection<T> col, Predicate<T> filter) {
    return col.stream().filter(Objects::nonNull).filter(filter).findFirst().orElse(null);
}

public static Options findEqualOptions(List<Options> list, Options opt) {
    return findByProperty(list, d -> d.hasSameOptions(opt));
}

После этого я пытаюсь сжать список еще больше, комбинируя элементы, которые имеют только ОДНУ другое значение.Например:

1 : 2 : A = 12
1 : 3 : A = 12 
 -> 1 : 23 : A = 12

я делаю это так:

for (int i = 0; i < list.size(); i++) {
    for (int j = i + 1; j < list.size(); j++) {
        Option o1 = list.get(i);
        Option o2 = list.get(j);
        int diff1 = 0;
        int diff2 = 0;
        int diff3 = 0;
        int diff4 = 0;


        if(!o1.opt1.equals(o2.opt1))
            diff1 = 1;
        if(!o1.opt2.equals(o2.opt2))
            diff2 = 1;

        //and so on

        if((diff1+diff2+diff3+diff4)>1)
            continue;

        if(diff1 == 1)
            o1.opt1 = o1.opt1 + o2.opt1;

        //and so on...


        list.remove(j--);


    }
}

я делаю это до тех пор, пока больше не будет изменений.Работает хорошо, но медленно.особенно метод cleanList ().Кто-нибудь есть идеи, как сделать это лучше?я попытался использовать поток, чтобы получить весь список опций равенства, например, так:

public static <T> List<T> findByMultipleValue(Collection<T> col, Predicate<T> filter) {
    return col.stream().filter(filter).collect(Collectors.toList());
}

public static List<Options> getEqualOptionsList(List<Options> optList, Options opt){
    return findByMultipleValue(optList, o -> o.hasSameOptions(opt));
}

, но это сделало его намного медленнее.

PS.Это не полный код, просто пример того, что я пытаюсь сделать.Надеюсь, на этот раз все более понятно:)

1 Ответ

0 голосов
/ 22 февраля 2019

, вероятно, не самое элегантное или оптимальное решение, но здесь уже есть быстрый подход, который дает результат на основе вашего описания.Он использует HashMap, как было предложено в комментарии @Joseph Larson

. Я выбрал набор символов, чтобы убедиться, что значения не повторяются в нем, но не стесняйтесь адаптироваться:)

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

class Scratch {
    public static class Option{
        String opt1;
        String opt2;
        String opt3;
        String optResult;

        public Option(String opt1, String opt2, String opt3, String optResult) {
            this.opt1 = opt1;
            this.opt2 = opt2;
            this.opt3 = opt3;
            this.optResult = optResult;
        }

        public static String merge(String a, String b){
            StringBuilder value = new StringBuilder();
            Set<Character> result = new HashSet<>();
            for(char c : a.toCharArray()){
                result.add(c);
            }
            for(char c : b.toCharArray()){
                result.add(c);
            }
            for(char c : result){
                value.append(c);
            }
            return value.toString();
        }

        public Option(Option a, Option b) {
            this(merge(a.opt1, b.opt1), merge(a.opt2, b.opt2), merge(a.opt3, b.opt3), merge(a.optResult, b.optResult));
        }

        String getKey(){
            return String.join(":", opt1, opt2, opt3);
        }

        int distance(Option option){
            int diff1 = this.opt1.equals(option.opt1)?0:1;
            int diff2 = this.opt2.equals(option.opt2)?0:1;
            int diff3 = this.opt3.equals(option.opt3)?0:1;
            int diff4 = this.optResult.equals(option.optResult)?0:1;
            return diff1 + diff2 + diff3 + diff4;
        }

        public String toString(){
            return getKey();
        }
    }
    public static void main(String[] args) {
        Option[] data = new Option[]{
                new Option("12", "45", "AB", "12"),
                new Option("12", "45", "AB", "3"),
                new Option("12", "45", "AB", "4"),
                new Option("12", "45", "AC", "1"),
                new Option("12", "45", "AC", "12"),
                new Option("3", "45", "AC", "13"),
                new Option("12", "45", "AD", "12"),
        };

        mergeExact(data);
        mergeClose(data, 1);
    }

    private static void mergeClose(Scratch.Option[] data, int distance){
        Map<Option, Set<Character>> buffer = new HashMap<>();
        for(Option option : data) {
            boolean found = false;
            Option toDelete = null;
            for(Map.Entry<Option, Set<Character>> entry : buffer.entrySet()){
                if(option.distance(entry.getKey()) <= distance){
                    Option merged = new Option(entry.getKey(), option);
                    for(char c : option.optResult.toCharArray()){
                        entry.getValue().add(c);
                    }
                    buffer.put(merged, entry.getValue());
                    toDelete = entry.getKey();
                    found = true;
                    break;
                }
            }
            if(found) {
                buffer.remove(toDelete);
            }else{
                Set<Character> set = new HashSet<>();
                for(char c : option.optResult.toCharArray()){
                    set.add(c);
                }
                buffer.put(option, set);
            }
        }
        System.out.println(String.format("merge with distance of %d:: %s", distance, buffer));

    }

    private static void mergeExact(Scratch.Option[] data) {
        Map<String, Set<Character>> buffer = new HashMap<>();
        for(Option option : data){
            Set<Character> item = buffer.computeIfAbsent(option.getKey(), k -> new HashSet<>());
            for(char c : option.optResult.toCharArray()){
                item.add(c);
            }
        }
        System.out.println("exact merge:: "+buffer);
    }


}

вывод

exact merge:: {3:45:AC=[1, 3], 12:45:AD=[1, 2], 12:45:AC=[1, 2], 12:45:AB=[1, 2, 3, 4]}
merge with distance of 1:: {12:45:AB=[1, 2, 3, 4], 3:45:AC=[1, 3], 12:45:ACD=[1, 2]}

РЕДАКТИРОВАТЬ: пропустил часть вопроса, обновляя, чтобы добавить слияние, когда разница близка.Эта часть, вероятно, даже хуже, чем первая с точки зрения оптимизации, но это рабочие основы:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...