回答編集履歴

2

表現の微調整

2020/03/11 10:55

投稿

xebme
xebme

スコア1083

test CHANGED
@@ -180,7 +180,7 @@
180
180
 
181
181
 
182
182
 
183
- 上のコードからcalculate()メソッドを削除しオペランドスタックをリストにかえてリストへ演算子を追加すると、逆ポーランド記法を生成できます。せっかくだから、逆ポーランド記法を生成して評価する関数型の実装紹介ます
183
+ 上のコードからcalculate()メソッドを削除しオペランドスタックをリストにかえてリストへ演算子を追加すると、逆ポーランド記法を生成できます。せっかくだから、逆ポーランド記法を生成して評価する関数型コード書いてみま
184
184
 
185
185
 
186
186
 
@@ -328,7 +328,7 @@
328
328
 
329
329
 
330
330
 
331
- 上で作成したList<Character>を入力する逆ポーランド記法の評価器(関数)を定義。
331
+ 上で作成したList<Character>を入力する逆ポーランド記法の評価器(関数)を定義。
332
332
 
333
333
 
334
334
 

1

逆ポーランド記法(追記)

2020/03/11 10:55

投稿

xebme
xebme

スコア1083

test CHANGED
@@ -171,3 +171,267 @@
171
171
  - [Parsing/RPN calculator algorithm](https://rosettacode.org/wiki/Parsing/RPN_calculator_algorithm)
172
172
 
173
173
  - [Parsing/Shunting-yard algorithm](https://rosettacode.org/wiki/Parsing/Shunting-yard_algorithm)
174
+
175
+
176
+
177
+ ##
178
+
179
+ **逆ポーランド記法(追記)**
180
+
181
+
182
+
183
+ 上のコードからcalculate()メソッドを削除しオペランドスタックをリストにかえてリストへ演算子を追加すると、逆ポーランド記法を生成できます。せっかくだから、逆ポーランド記法を生成して評価する関数型の実装を紹介します。
184
+
185
+
186
+
187
+ 演算に除算`/`を追加して優先度を以下のように決定。
188
+
189
+
190
+
191
+ ```Java
192
+
193
+ static Function<Character,Integer> priority =
194
+
195
+ operator -> (operator == '*' || operator == '/') ? 2
196
+
197
+ : (operator == '+' || operator == '-') ? 1 : 0;
198
+
199
+
200
+
201
+ static BiFunction<Character,Character,Boolean> preceding =
202
+
203
+ (op1,op2) -> priority.apply(op1) >= priority.apply(op2);
204
+
205
+ ```
206
+
207
+
208
+
209
+ 逆ポーランド記法の生成器(関数)を定義する。逆ポーランド記法として出力されるのはList<Character>。
210
+
211
+
212
+
213
+ ```Java
214
+
215
+ static Function<String,List<Character>> toRpn = expression -> {
216
+
217
+ Deque<Character> operators = new LinkedList<>(); // キャプチャされる。
218
+
219
+ List<Character> rpnList = expression.chars()
220
+
221
+ .mapToObj(c -> Character.valueOf((char) c))
222
+
223
+ .collect(
224
+
225
+ ArrayList::new,
226
+
227
+ (accList, token) -> {
228
+
229
+ switch (token) {
230
+
231
+ case ' ':
232
+
233
+ break;
234
+
235
+ case '(':
236
+
237
+ operators.push(token);
238
+
239
+ break;
240
+
241
+ case ')':
242
+
243
+ while (!operators.isEmpty()) {
244
+
245
+ char operator = operators.pop();
246
+
247
+ if (operator == '(') {
248
+
249
+ break;
250
+
251
+ }
252
+
253
+ accList.add(operator);
254
+
255
+ }
256
+
257
+ break;
258
+
259
+ case '0':
260
+
261
+ case '1':
262
+
263
+ case '2':
264
+
265
+ case '3':
266
+
267
+ case '4':
268
+
269
+ case '5':
270
+
271
+ case '6':
272
+
273
+ case '7':
274
+
275
+ case '8':
276
+
277
+ case '9':
278
+
279
+ accList.add(token);
280
+
281
+ break;
282
+
283
+ case '+':
284
+
285
+ case '-':
286
+
287
+ case '*'
288
+
289
+ case '/':
290
+
291
+ if (!operators.isEmpty() && preceding.apply(operators.peek(), token)) {
292
+
293
+ accList.add(operators.pop());
294
+
295
+ }
296
+
297
+ operators.push(token);
298
+
299
+ break;
300
+
301
+ default: //
302
+
303
+ throw new RuntimeException("Invalid token : '" + token + "' in '" + expression + "'");
304
+
305
+ }
306
+
307
+ },
308
+
309
+ List::addAll);
310
+
311
+ while (!operators.isEmpty()) {
312
+
313
+ rpnList.add(operators.pop());
314
+
315
+ }
316
+
317
+ return rpnList;
318
+
319
+ };
320
+
321
+
322
+
323
+ ```
324
+
325
+
326
+
327
+ **逆ポーランド記法の評価**
328
+
329
+
330
+
331
+ 上で作成したList<Character>を入力にする逆ポーランド記法の評価器(関数)を定義。
332
+
333
+
334
+
335
+ ```Java
336
+
337
+ static Function<List<Character>,Integer> evalRpn = rpn -> {
338
+
339
+ Deque<Integer> result =
340
+
341
+ rpn.stream()
342
+
343
+ .collect(
344
+
345
+ LinkedList::new,
346
+
347
+ (operandStack, token) -> {
348
+
349
+ switch (token) {
350
+
351
+ case '0':
352
+
353
+ case '1':
354
+
355
+ case '2':
356
+
357
+ case '3':
358
+
359
+ case '4':
360
+
361
+ case '5':
362
+
363
+ case '6':
364
+
365
+ case '7':
366
+
367
+ case '8':
368
+
369
+ case '9':
370
+
371
+ operandStack.push(token - '0');
372
+
373
+ break;
374
+
375
+ case '+':
376
+
377
+ operandStack.push(operandStack.pop() + operandStack.pop());
378
+
379
+ break;
380
+
381
+ case '-':
382
+
383
+ operandStack.push(-operandStack.pop() + operandStack.pop());
384
+
385
+ break;
386
+
387
+ case '*':
388
+
389
+ operandStack.push(operandStack.pop() * operandStack.pop());
390
+
391
+ break;
392
+
393
+ case '/':
394
+
395
+ operandStack.push((int)(1d / operandStack.pop() * operandStack.pop()));
396
+
397
+ break;
398
+
399
+ }
400
+
401
+ },
402
+
403
+ Deque::addAll);
404
+
405
+ return result.pop();
406
+
407
+ };
408
+
409
+ ```
410
+
411
+
412
+
413
+ 逆ポーランド記法の生成と評価を合成。
414
+
415
+
416
+
417
+ ```Java
418
+
419
+ static Function<String,Integer> eval = toRpn.andThen(evalRpn);
420
+
421
+ ```
422
+
423
+
424
+
425
+ 利用方法。
426
+
427
+
428
+
429
+ ```Java
430
+
431
+ String expression = "2 * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9)";
432
+
433
+ int result = eval.apply(expression);
434
+
435
+ System.out.println(expression + " = " + result);
436
+
437
+ ```