Nano Hash - криптовалюты, майнинг, программирование

Поиск нескольких значений в классе данных в ArrayList

У меня есть ArrayList из Customs заказов, как показано ниже

ArrayList<Customs> customsList = new ArrayList<Customs>();

Пример моего таможенного класса

public class Customs
{
    private String  userId;

    private String  customLabel;
    private Double  itemPrice;
    private Double  weight;

//getters and setters
}

customsList может содержать несколько объектов Customs, которые могут иметь одинаковые uesrId, что указывает на то, что они принадлежат одному и тому же клиенту.

Я пытаюсь написать метод, который проверяет, повторяется ли в ArrayList более одного идентификатора пользователя, и если он повторяется более одного раза, он добавляет их itemPrice и вес вместе, а затем помещает его в другой список как один.

Как лучше всего это сделать?

02.08.2015

  • Вместо того, чтобы просить о решении вашей проблемы, покажите нам решение, которое вы пробовали, и задайте конкретный вопрос о том, почему оно работает не так, как вам хотелось бы. 02.08.2015
  • @scottb: В этом сценарии это не совсем необходимо. Это все равно, что ожидать, что кто-то знает все об этой проблеме — если бы знал, зачем спрашивать? 02.08.2015
  • возможный дубликат Поиск повторяющихся значений в arraylist 02.08.2015
  • @durron597: Нет, даже не близко. 02.08.2015
  • @Makoto Мне нужно найти, есть ли в списке автомобили с таким же названием. напишите метод, который проверяет, повторяется ли в ArrayList более одного идентификатора пользователя. Они обе строки, даже. 02.08.2015
  • @durron597: Вам не хватает второй половины — объединения элементов в один универсальный элемент. Методы, описанные в вашем связанном дубликате, не способны выразить это. 02.08.2015
  • Мне нравится, как легко c# и LINQ сделают это... 02.08.2015
  • @BenKnoble С Java 8 вы также можете сделать это в одну строку. 02.08.2015
  • @pbabcdefp честно. Мои знания Java 8 более ограничены. Но тем не менее, вы должны восхищаться инструментами C#. 02.08.2015
  • @Makoto: вопрос сильно напоминает домашнюю задачу. Ценность поиска ответа на такие проблемы значительно возрастает при поиске решения с использованием знаний, которые, как предполагается, уже есть. Я также с осторожностью отношусь к сдержанности ОП в поисках ответов на существующие вопросы. 02.08.2015
  • @scottb: На самом деле не имеет значения, является ли это проблемой домашнего задания или нет. В реальном мире существуют сценарии, в которых знание того, как это сделать, бесконечно ценно. 02.08.2015
  • @Makoto: ну ладно... но это действительно имеет значение. Я бы предпочел, чтобы сотрудник был самостоятельным и способным самостоятельно решать проблемы, чем сотрудник, который ожидал, что проблемы всегда будут решены за него. Готовность попытаться прийти к собственному решению, прежде чем спрашивать, является хорошим свидетельством такой ценной инициативы, не так ли? 02.08.2015
  • Для этого есть масса решений, для них ему даже не нужно консультироваться со stackoverflow.com. 02.08.2015
  • Это, очевидно, не вопрос домашнего задания, и да, я могу сделать эту работу, используя старомодные методы. Причина, по которой я разместил это здесь, заключается в том, что я думал, что получу самый чистый способ сделать это. Я еще не знаком с функциями Java 8 и видел, насколько это может уменьшить размер кода. 02.08.2015
  • Хотя вы можете сделать это в одну строку, я бы не рекомендовал это делать, так как это будет очень сложная строка. Я бы поискал Map.merge. Это позволит вам легко создать Map с userId в качестве ключей и комбинированными ценами/весами в качестве значений. 02.08.2015

Ответы:


1

Хм, есть хитрый способ сделать это с помощью distinct, переопределяя hashCode и equals. Нужно заботиться об этом, когда нужен другой вид для вашего класса.

public class Test {
    public static void main(String[] args) {
        ArrayList<Customs> customsList = new ArrayList<Customs>();
        Customs c1 = new Customs(123L, "bad", 23d, 34d);
        Customs c2 = new Customs(122L, "bad", 23d, 34d);
        Customs c3 = new Customs(125L, "bad", 23d, 34d);
        Customs c4 = new Customs(122L, "bad", 23d, 34d);
        Customs c5 = new Customs(122L, "bad", 23d, 34d);
        Customs c6 = new Customs(123L, "bad", 23d, 34d);
        customsList.add(c1);
        customsList.add(c2);
        customsList.add(c3);
        customsList.add(c4);
        customsList.add(c5);
        customsList.add(c6);

        customsList.stream().distinct().collect(Collectors.toList()).forEach(t -> {
                    System.out.println(t.getUserId());
                    System.out.println(t.getItemPrice());
                    System.out.println(t.getWeight());
                }
        );
    }
}

class Customs {
    private long userId;

    private String customLabel;
    private Double itemPrice;
    private Double weight;

    public Customs(long userId, String customLabel, Double itemPrice, Double weight) {
        this.userId = userId;
        this.customLabel = customLabel;
        this.itemPrice = itemPrice;
        this.weight = weight;
    }

    public long getUserId() {
        return userId;
    }

    public void setUserId(long userId) {
        this.userId = userId;
    }

    public String getCustomLabel() {
        return customLabel;
    }

    public void setCustomLabel(String customLabel) {
        this.customLabel = customLabel;
    }

    public Double getItemPrice() {
        return itemPrice;
    }

    public void setItemPrice(Double itemPrice) {
        this.itemPrice = itemPrice;
    }

    public Double getWeight() {
        return weight;
    }

    public void setWeight(Double weight) {
        this.weight = weight;
    }

    @Override
    public boolean equals(Object o) { //Override equals method for distinct, at the same time add the weight and itemPrice, it's a tricky way. if you want to do that, you need to make sure, there will be no other sort need.
        if (!(o instanceof Customs)) {
            return false;
        }
        Customs c = (Customs) o;
        if (this.userId == c.userId) {
            c.itemPrice += this.itemPrice;
            c.weight += this.weight;
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() { //Override hashCode for distinct
        return Long.valueOf(this.userId).hashCode();
    }


//getters and setters
}
02.08.2015

2

Есть вероятно однострочник для Java 8, но я предпочитаю избегать его, если мне это нужно. Обратите внимание, что это решение предназначено исключительно для Java 8.

По сути, процесс, которому вы должны следовать:

  • Разделите ваши элементы на соответствующие сегменты (по идентификатору пользователя)
  • Соедините элементы вместе
  • Возвращает новый список, содержащий отдельный элемент.

Вы не указываете, какой customLabel выигрывает в целом, но вот подход, который объединяет его с последним.

Добавьте этот метод в Customs:

public void combine(Customs another) {
    this.userId = another.getUserId();
    this.customLabel = another.getCustomLabel();
    this.itemPrice = null == this.itemPrice ? another.getItemPrice() : this.itemPrice + another.getItemPrice();
    this.weight = null == this.weight ? another.getWeight() : this.weight + another.getWeight();
}

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

final Map<String, List<Customs>> groupedCustomsElements = customsList.stream()
                                                                     .collect(Collectors.groupingBy(Customs::getUserId));
final List<Customs> combinedResult = new ArrayList<>();
for (String s : groupedCustomsElements.keySet()) {
    combinedResult.add(groupedCustomsElements.get(s)
                                             .stream()
                                             .collect(Customs::new, Customs::combine, Customs::combine));
}

Более простым решением может быть создание собственного пользовательского списка, который расширяет ArrayList и дополняет метод add в соответствии с вашими потребностями.

class CustomCombiningList extends ArrayList<Customs> {

    @Override
    public boolean add(Customs e) {
        int idx = indexOf(e);
        if(idx != -1) {
            add(idx, get(idx).combineAndReturn(e));
            remove(idx + 1); // clean up unneeded object; worth a unit test
        } else {
            super.add(e);
        }
        return true;
    }
}

Для этого потребуются два новых метода — combineAndReturn, который фактически возвращает результат combine, и определение equals() для вашего элемента Customs. Это может быть красивее для чтения, чем запутанная лямбда.

02.08.2015
  • @pbabcdefp: Спасибо за совет по super - я как-то пропустил это, когда печатал невероятно быстро. Что касается расширения списка - это должно быть хорошо; если кто-то не хочет прибегать к инвазивному и серьезно запутанному подходу, то это альтернатива этому. 02.08.2015

  • 3

    Я не буду повторять ответ Макото о том, как это сделать в Java8. Вот как это сделать в Java 6:

        Map<String, Customs> groupedCustoms = new LinkedHashMap<String, Customs>();
    
        for (Customs custom : customs) {
            Customs aggrCustom = groupedCustoms.get(custom.getUserId());
            if (aggrCustom == null) {
                // create new aggregated record
                aggrCustom = new Customs(custom);
                groupedCustoms.put(custom.getUserId(), aggrCustom);
            } else {
                aggrCustom.aggregateWith(custom);
            }
        }
    
        List<Custom> results = new ArrayList<Customs>(groupedCustoms.values());
    

    Я предполагаю, что исходные начальные Customs хранятся в List<Customs> customs. Также я предполагаю, что в Customs есть конструктор копирования, который принимает еще один Customs в качестве аргумента и копирует его поля (аналог clone), и метод aggregateWith, который принимает еще один Customs в качестве аргумента и добавляет свои метрические поля к текущему.

    Использование LinkedHashMap для группировки записей необходимо для того, чтобы сделать группировку "стабильной", т.е. сохранить первоначальный порядок записей.

    02.08.2015
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..