I want to iterate through a file that has key/value pairs and put them into a Map.
The file contains values like so:
forward 5
up 4
down 3
down 6
forward 4
...
Here is my code:
private static void depthPosition() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("/Users/WorkAcc/Desktop/file.txt"));
String lines;
Map<String, Integer> instructions = new HashMap<>();
String [] pair;
while ((lines = bufferedReader.readLine()) != null) {
pair = lines.split(" ");
instructions.put(pair[0], Integer.valueOf(pair[1]));
}
System.out.println(instructions);
}
}
The problem I am having is that the Map called instructions
is not adding new values from the file, it stops at size 3, not sure why.
Would appreciate some help here. Thanks!
CodePudding user response:
This is an example of how you can calculate what you indicate in the comments.
public void depthPosition() throws IOException {
int value = 5;
List<Instruction> instructions = readInstructionsFromFile("/Users/WorkAcc/Desktop/file.txt");
int result = calculateDepthPosition(instructions, value);
System.out.println("result is: " result);
}
private List<Instruction> readInstructionsFromFile(String filePath) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String line;
Instruction instruction;
List<Instruction> instructions = new ArrayList<>();
String[] pair;
while ((line = bufferedReader.readLine()) != null) {
pair = line.split(" ");
instruction = new Instruction(pair[0], Integer.valueOf(pair[1]));
instructions.add(instruction);
}
return instructions;
}
private int calculateDepthPosition(List<Instruction> instructions, int value){
int nextValue = value;
int result = value;
for (Instruction instruction : instructions) {
nextValue = instruction.apply(nextValue);
result = Math.min(result, nextValue);
}
return result;
}
public static class Instruction {
private String type;
private int amount;
public Instruction(String type, int amount) {
this.type = type;
this.amount = amount;
}
public int apply(int value) {
switch (type) {
case "forward":
return value amount;
case "down":
return value - amount;
case "up":
return value ?? amount;
default:
return value;
}
}
}
CodePudding user response:
As was mentioned in the comments, duplicate keys are not permitted in maps.
If you want to read in those strings and maintain order (which would seem likely), you can do it like this.
- create a
record
(immutable class) to hold the direction and amount. A regular class could also be used. - instantiate a Scanner to read the file (I am reading from a String for demo purposes).
- create a
List
to hold the records. In this case an ArrayList - then iterate over the file as follows.
String s = "forward 5\n up 4\n down 3\n down 6\n forward 4\n";
record Info(String direction, int amount){
@Override
public String toString() {
return "[%s, %s]".formatted(direction, amount);
}
}
Scanner input = new Scanner(s);
List<Info> list = new ArrayList<>();
while(input.hasNextLine()) {
list.add(new Info(input.next(), input.nextInt()));
input.nextLine(); // consume end of line marker
} while(input.hasNextLine());
list.forEach(System.out::println);
prints
[forward, 5]
[up, 4]
[down, 3]
[down, 6]
[forward, 4]
You can also interate and get the individual values like so.
for (Info info : list) {
System.out.println(info.direction() " " info.amount());
}
prints
forward 5
up 4
down 3
down 6
forward 4
Note: The above solution presumes each line is well defined and contains a String
and an int
per line, separate by one or more spaces. Otherwise, an exception would likely be thrown.
Updated
Once I store the above data, I want to read it in order and do calculations based on the first parameter eg if forward then I add to the number, if down then I subtract from the number etc.
Based on the above added comment you can do it like the following (you may have to adjust the commands somewhat to fit your file).
You can also achieve the following result by iterating of the list
created above and processing each line in a switch statement.
- create a map to hold the values.
- use
Files.lines
to stream the lines for processing - using mapMulti to process each line.
- first split into a two parts
- capture the count and the direction
- if the direction is down, convert to up and change the sign.
- for positive directions, use as is. (Note. no counter direction given for
forward
- then create a Map entry and insert into the stream.
- collect in a map, summing the values
Map<String,Integer> map = null;
try {
map = Files.lines(Path.of("f:/inputFile.txt"))
.<Map.Entry<String,Integer>>mapMulti((str, consumer) -> {
String[] arr = str.split("\\s ");
int count = Integer.valueOf(arr[1]);
Map.Entry<String, Integer> entry =
switch (arr[0]) {
case "forward","up"-> Map.entry(arr[0],
count);
case "down" -> Map.entry("up", -count);
default -> Map.entry("up, 0); // innocuous entry.
};
consumer.accept(entry);
}).collect(Collectors.toMap(Entry::getKey, Entry::getValue, Integer::sum));
} catch (Exception e) {
e.printStackTrace();
}
map.entrySet().forEach(System.out::println);
prints (the positive directions are used as keys).
forward=9
up=-5