Разбор строки с использованием HashMap для форматирования - PullRequest
1 голос
/ 27 февраля 2020

Я пишу Java форматировщик строки, и я думаю, что я делаю это более сложным, чем это может быть? У меня есть файл, который дает список магазинов:

"100|Pete's Pizza Palace|George Smith|200"
"400|Pete's Pizza Palace|George Smith|30"
"320|Pete's Pizza Palace|George Smith|-13"
"310|Pete's Pizza Palace|John Smith|2"

Вывод должен выглядеть так: «Пицца Пицца Палас | Джордж Смит | 217, Пицца Пита Палаца | Джон Смит | 2»

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

static String fileRecords(String[] records) {
    int len = records.length;
    Map<String, Integer> map = new HashMap<String, Integer>();
    Map<String, Integer> profitTotals = new HashMap<String, Integer>();
    String[] record = new String[len];
    int index = 0;
    int[] sums = new int[len];
    StringBuilder sb = new StringBuilder();
    StringBuilder tempStringBuilder = new StringBuilder();
    int totalSum = 0;
    for(int i = 0;i<len;i++) {
        record = records[i].split("\\|");
        String recEntryNameString = tempStringBuilder.append(record[1]).append("|").append(record[2]).append("|").toString();
        map.put(recEntryNameString, Integer.parseInt(record[3]));   
        profitTotals.put(recEntryNameString, Integer.parseInt(record[3])); 
        Iterator iter = map.entrySet().iterator();
        for (Map.Entry<String, Integer> entries : map.entrySet()) {
            for(Map.Entry<String, Integer> sumNum : profitTotals.entrySet()) {
                if(!entries.getKey().equals(sumNum.getKey())) {
                    totalSum = entries.getKey() + sumNum.getKey();
                    map.replace(recEntryNameString, entries.getKey(), totalSum);    
                    profitTotals.remove(recEntryNameString);
                }
            }
        }
    }
    Iterator<String, Integer> iter = map.entrySet().iterator();
    while(iter.hasNext()) {
        Map.Entry<String, Integer> entry = iter.next();
        if(iter.hasNext()==true)
            sb.append(entry.getKey()).append(entry.getValue()).append(",");
        else
            sb.append(entry.getKey()).append(entry.getValue());
    }
    return sb.toString();
}

Я получаю очень близкие результаты, но снова ищу правильный формат

Pete's Pizza Palace|George Smith|Pete's Pizza Palace|George Smith|Pete's Pizza Palace|George 
Smith|87,Pete's Pizza Palace|George Smith|100,Pete's Pizza Palace|George Smith|Pete's Pizza 
 Palace|George Smith|123,

Ответы [ 4 ]

3 голосов
/ 27 февраля 2020

Сначала представьте эти данные в классе:

public class Transaction {
    private int id;
    private String place;
    private String customer;
    private double amount;

    Transaction(String tokenizedString) {
        String[] tokens = tokenizedString.split("\\|");
        id = Integer.parseInt(tokens[0]);
        place = tokens[1];
        customer = tokens[2];
        amount = Double.parseDouble(tokens[3]);
    }

    //getters/setters
}

, затем вы можете использовать их следующим образом:

public static void main(String[] args) {
    List<String> list = List.of(
            "100|Pete's Pizza Palace|George Smith|200",
            "400|Pete's Pizza Palace|George Smith|30",
            "320|Pete's Pizza Palace|George Smith|-13",
            "310|Pete's Pizza Palace|John Smith|2"
    );
    Map<String, Double> map = list.stream()
            .map(Transaction::new)
            .collect(Collectors.groupingBy(
                    o -> String.join("|", o.getPlace(), o.getCustomer()),
                    Collectors.summingDouble(Transaction::getAmount)));
    List<String> result = map.entrySet().stream()
            .map(e -> e.getKey() + "|" + e.getValue())
            .collect(Collectors.toList());
    System.out.println(result);
}

Вывод :

[Pete's Pizza Palace|George Smith|217.0, Pete's Pizza Palace|John Smith|2.0]

Пояснение :

.map(Transaction::new)
преобразует каждый элемент в списке строк в Transaction, благодаря параметризованному конструктору.

Тогда я сгруппированные транзакции по объединенной строке place и customer, разделенной вашим разделителем |.
. Это дало мне карту, содержащую записи типа "Pete's Pizza Palace|George Smith" -> 217.0

Наконец, я сопоставил каждую запись с строка, которая является результатом объединения ключа и значения, разделенных |, и сбора их в список.

Я пытался выполнить этот последний шаг сбора в список внутри нисходящего коллектора groupingBy, но не смог найти способ.

0 голосов
/ 27 февраля 2020

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

  static String fileRecords(String[] records) {
    return Arrays.stream(records)
        .map(record -> record.split("\\|"))
        .collect(groupingBy(fields -> fields[1] + "|" + fields[2], summingInt(fields -> Integer.parseInt(fields[3]))))
        .entrySet().stream()
        .map(entry -> entry.getKey() + "|" + entry.getValue())
        .collect(joining(","));
  }

Этот поток вполне поддается параллелизации. Для параллельной обработки больших массивов записей вы можете просто добавить .parallel() после Arrays.stream(records) и entrySet().stream()

0 голосов
/ 27 февраля 2020

Мне очень нравится ответ Kartik на использование новых функций в языке Java.

Немного проще для понимания может быть:

public class PizzaStore {

static String[] records = new String[]{"100|Pete's Pizza Palace|George Smith|200",
    "400|Pete's Pizza Palace|George Smith|30",
    "320|Pete's Pizza Palace|George Smith|-13",
    "310|Pete's Pizza Palace|John Smith|2"};

public static void main(String[] args) {
    fileRecords(records);
}

static void fileRecords(String[] records) {

    int len = records.length;

    HashMap<String, Integer> runningTotals = new HashMap<>();

    for (int i = 0; i < len; i++) {
        String rec = records[i];
        String[] fields = rec.split("\\|");
        String storeName = fields[1] + "|" + fields[2];
        Integer value = new Integer(fields[3]);
        if (!runningTotals.containsKey(storeName)) {
            runningTotals.put(storeName, 0);            
        }
        runningTotals.put(storeName, runningTotals.get(storeName) + value);
    }

    for (String s : runningTotals.keySet()) {
        System.out.println(s + "|" + runningTotals.get(s));
    }

}
}

Здесь мы используем понимание (благодарность Картику), что две средние струны могут быть соединены, чтобы сформировать ключ.

Вывод выглядит так:

Pete's Pizza Palace | George Smith | 217

Pete's Pizza Palace | John Smith | 2

например, разделенные на разные строки, но это легко настраивается (измените println на принт и вставьте между ними "|".

0 голосов
/ 27 февраля 2020

Я бы создал промежуточный объект в качестве держателя данных для хранения записей

class PizzaStore {

    int storeID;
    String franchiseName;
    String managerName;
    // if this is supposed to be a currency value use BigDecimal instead
    int profitability;

 }

Большинство IDE могут добавлять методы установки и получения, если вы хотите сделать их защищенными или частными.

Затем вам нужен конструктор, чтобы превратить вашу запись в пиццерию

     public PizzaStore(String record) {
         if (record == null) {
             // initialize to default values and return
             // don't want to throw exceptions in constructors
             // ...
             return;
         }

         String[] fields = record.split("\\|");

         if (fields.length < 4) {
             // initialize to default values and return
             // don't want to throw exceptions in constructors
             // ...
             return;
         }

         this.franchiseName = fields[1];
         this.managerName = fields[2];


         try {
             Integer id = new Integer(fields[0]);
             Integer profit = new Integer(fields[3]);
         } catch (Exception e) {
             System.err.println("failed to parse fields: " + fields[0] + " - " + fields[3]);    
             // initialise them to something
         }
     }

А затем вам нужна структура данных для их хранения. Вы можете использовать массив, но если вы собираетесь извлечь их из структуры данных с помощью storeID (например) и storeID уникален, то вы можете создать HashMap и поместить номер магазина в качестве ключа, а магазин пиццы как значение.

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