Как бороться с такими же ключами в HashMaps? - PullRequest
0 голосов
/ 17 мая 2018

Здравствуйте, соратники.

Очевидно, что ключи в хэш-картах уникальны . Тем не менее, я пытался написать код, который читает файл CSV, а затем помещает ключ и значение в карту. Однако, есть одинаковые ключи (каждый ключ в файле csv равен 15 раз). В этом случае он должен сделать сумму значений и просто вернуть ключ один раз. Как это сделать? Мой код сейчас выглядит следующим образом.

BufferedReader br = null;
String line;



    try {
        br = new BufferedReader(new FileReader(filepath)); 

    } catch (FileNotFoundException fnfex) {

        System.out.println(fnfex.getMessage() + "Bestand niet gevonden!");
        System.exit(0);
    }

    //this is where we read lines
    try {
        while((line = br.readLine()) != null) {
            String[] splitter = line.split(cvsSplitBy);

            if(splitter[0] != "Voertuig") {

                alldataMap.put(splitter[0], splitter[8]);

        }


            //MIGHT BE JUNK, DONT KNOW YET
            /*if((splitter[0].toLowerCase()).contains("1")){
                double valuekm = Double.parseDouble(splitter[8]);
                license1 += valuekm;
                System.out.println(license1);
            }
            else {
                System.out.println("not found");
            }*/


        }
        System.out.println(alldataMap);
        TextOutput();
    } catch (IOException ioex) {
        System.out.println(ioex.getMessage() + " Error 1");
    } finally {
        System.exit(0);
    }

Так что, если у меня есть следующая информация (в этом случае 0-е и 8-е слово читают каждую строку в файле CSV)

Apples; 299,9
Bananas; 300,23
Apples; 3912,1
Bananas;342
Bananas;343

Должен вернуться

Apples;Total
Bananas;Total

Ответы [ 5 ]

0 голосов
/ 17 мая 2018

Я не буду предлагать путь к нему в цикле, потому что это уже сделано, но я бы предложил Streams решение в уникальной строке:

Map<String, Double> alldataMap = new HashMap<>();
try {
    alldataMap =
            Files.lines(Paths.get("", filepath))
                    .map(str -> str.split(cvsSplitBy))
                    .filter(splitte -> !splitte[0].equals("Voertuig"))
                    .collect(Collectors.toMap(sp -> sp[0],
                            sp -> Double.parseDouble(sp[8].replaceAll(",", ".")),
                            (i1, i2) -> i1 + i2));
} catch (IOException e) {
    e.printStackTrace();
}

System.out.println(alldataMap); // {Apples=4212.0, Bananas=985.23}

Шаги одинаковы:

  • Итерация по строкам
  • разделение на cvsSplitBy
  • удаление строк, начинающееся с Voertuig (! использовать .equals(), а не !=)
  • построить карту, следуя 3 правилам:
    • ключ первый String
    • значениесекунда String анализируется как Double
    • , если требуется объединение: сумма

Изменить, поскольку никто не предлагает использовать .getOrDefault() Я даю это

while ((line = br.readLine()) != null) {
    String[] splitter = line.split(cvsSplitBy);
    if (!splitter[0].equals("Voertuig")) {
        alldataMap.put(splitter[0],
           alldataMap.getOrDefault(splitter[0], 0.0) + 
                                    Double.parseDouble(splitter[8].replaceAll(",", ".")));
    }
}

Если ключ tke уже существует, он суммируется, если ключ не существует, он суммирует значение с 0

0 голосов
/ 17 мая 2018

я бы использовал merge для карты:

alldataMap.merge(splitter[0], Double.valueOf(splitter[8]), (oldVal, newVal) -> oldVal + newVal);

С документ :

Если указанный ключ еще не связан сзначение или связано с нулем, связывает его с заданным ненулевым значением.В противном случае заменяет связанное значение результатами данной функции переназначения или удаляет, если результат равен нулю.Этот метод может быть полезен при комбинировании нескольких сопоставленных значений для ключа.Например, чтобы создать или добавить строковое сообщение к отображению значения:

0 голосов
/ 17 мая 2018

Вы можете использовать putIfAbsent и compute начиная с Java 8:

Map<String, Integer> myMap = new HashMap<>();

//...

String fruitName = /*whatever*/;
int qty = /*whatever*/;

myMap.putIfAbsent(fruitName, 0);
myMap.compute(fruitName, (k, oldQty) -> oldQty + qty);
0 голосов
/ 17 мая 2018

Попробуйте следующее:

if( alldataMap.containsKey(splitter[0]) ) { 
  Double sum = alldataMap.remove(splitter[0]) + Double.parseDouble(splitter[8]);
  allDataMap.put(splitter[0], sum );
} else {
  alldataMap.put(splitter[0], Double.valueOf(splitter[8]) );
}
0 голосов
/ 17 мая 2018

Вы можете использовать Map#containsKey(), чтобы проверить существующее сопоставление, затем, если есть одно, используйте Map#get(), чтобы получить значение и добавить новое, и, наконец, Map#put(), чтобы сохранить сумму:

if(map.containsKey(key))
    map.put(key, map.get(key)+value);
else
    map.put(key, value);

См. здесь для документации этих методов.

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