I have a list of num and string of operator above:
final List<dynamic> items = [5.0, "-", 2, "*", 3];
I want to calculate the value inside of it. I can do like this:
final List<dynamic> items = [5.0, "-", 2, "*", 3]; //correct is -1
num result = 0;
String op = "+";
for (final item in items) {
if (item is String) {
op = item;
}
if (item is num) {
switch (op) {
case "+":
result = result + item;
break;
case "-":
result = result - item;
break;
case "*":
result = result * item;
break;
case "/":
result = result / item;
break;
}
}
}
print(result); // incorrect result: 9
As above code, If it is just an "+" or "-" operator it would return the correct answer, but because of the order of operators "/" and "*" doing like above return incorrect result.
Can anyone suggest any algorithm?
Here is one way of doing it, the code works but I didn't put the tests that would be necessary to check for bad input.
// functions for basic operations
num multiply(num leftOp, num rightOp) => leftOp * rightOp;
num divide(num leftOp, num rightOp) => leftOp / rightOp;
num add(num leftOp, num rightOp) => leftOp + rightOp;
num substract(num leftOp, num rightOp) => leftOp - rightOp;
void main() {
final List<dynamic> items = [
2,
"*",
5,
"/",
2,
"-",
3,
"+",
8
]; //correct is 10
num result = 0;
// Copy the list in a temporary list
var calc = [...items];
// set the precedence order of the operators
// create 2 groups of equal importance
var operators = [
{
"*": multiply,
"/": divide,
},
{
"+": add,
"-": substract,
}
];
// loop until all operators have produced result
while (calc.length > 1) {
for (var opPrecedence in operators) {
// find first operator in a group, starting from left
var pos = 0;
do {
pos = calc.indexWhere((e) => opPrecedence.containsKey(e));
if (pos >= 0) {
num leftOp = calc[pos - 1];
num rightOp = calc[pos + 1];
var operation = opPrecedence[calc[pos]];
result = operation!(leftOp, rightOp);
// remove the 2 operands and replace with result
calc.removeAt(pos);
calc.removeAt(pos);
calc[pos - 1] = result;
}
} while (pos >= 0);
}
}
// what should be left is the final result
print(calc[0]);
}
You can create your own simple calculator parser for this purpose and use it.
Building (generation) of the parser will take less than one second.
You can always modify it to suit your needs and generate an updated parser.
Below is an example of definition such a parser.
It contains (also for example) a value calculation for your data (as an expression).
This script will generate a parser into example/calculator.dart.
File tool/calculator_builder.dart:
import 'package:parser_builder/branch.dart';
import 'package:parser_builder/bytes.dart';
import 'package:parser_builder/char_class.dart';
import 'package:parser_builder/character.dart';
import 'package:parser_builder/combinator.dart';
import 'package:parser_builder/error.dart';
import 'package:parser_builder/expression.dart';
import 'package:parser_builder/fast_build.dart';
import 'package:parser_builder/parser_builder.dart';
import 'package:parser_builder/sequence.dart';
Future<void> main(List<String> args) async {
final context = Context();
return fastBuild(context, [_parse, _expression_], 'example/calculator.dart',
header: __header, publish: {'parse': _parse});
}
const __header = '''
import 'package:source_span/source_span.dart';
import 'package:tuple/tuple.dart';
void main() {
final List items = [5.0, "-", 2, "*", 3];
final source = items.join(' ');
final result = parse(source);
print(result);
}
num _calculate(num left, String operator, num right) {
switch (operator) {
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
case '~/':
return left ~/ right;
default:
throw StateError('Unknown operator: \$operator');
}
}
''';
const _additive = Named(
'_additive',
BinaryExpression(
_multiplicative, _additiveOperator, _multiplicative, _calculate));
const _additiveOperator =
Named('_additiveOperator', Terminated(Tags(['+', '-']), _ws));
const _calculate = ExpressionAction<num>(
['left', 'op', 'right'], '_calculate({{left}}, {{op}}, {{right}})');
const _closeParen = Named('_closeParen', Terminated(Tag(')'), _ws));
const _decimal = Named(
'_decimal',
Terminated(
Map1(
Recognize(
Tuple3(Digit1(), Tag('.'), Digit1()),
),
ExpressionAction<num>(['x'], 'num.parse({{x}})')),
_ws));
const _expression = Ref<String, num>('_expression');
const _expression_ = Named('_expression', _additive);
const _integer = Named(
'_integer',
Terminated(
Map1(Digit1(), ExpressionAction<num>(['x'], 'int.parse({{x}})')), _ws));
const _isWhitespace = CharClass('#x9 | #xA | #xD | #x20');
const _multiplicative = Named('_multiplicative',
BinaryExpression(_primary, _multiplicativeOperator, _primary, _calculate));
const _multiplicativeOperator =
Named('_multiplicativeOperator', Terminated(Tags(['*', '/', '~/']), _ws));
const _openParen = Named('_openParen', Terminated(Tag('('), _ws));
const _parse = Named('_parse', Delimited(_ws, _expression, Eof<String>()));
const _primary = Named(
'_primary',
Nested(
'expression',
Alt3(
_decimal,
_integer,
Delimited(_openParen, _expression, _closeParen),
)));
const _ws = Named('_ws', SkipWhile(_isWhitespace));
If you run example/calculator.dart you will get the result.
-1.0
You can modify the build script and generate it as a library (eg as lib/calculator.dart).
Then import this library and use it.
It requires some programming skills from you, but there is nothing difficult about it.
Everything is very simple.
By combined ManuH68 answer I did:
void main() {
test('Return correct', () {
const correctResult = 10;
final calc = <dynamic>[2, "*", 5, "/", 2, "-", 3, "+", 8];
num result = 0;
// clean "*" and "/" first
while (calc.contains("*") || calc.contains("/")) {
final pos = calc.indexWhere((e) => e == "*" || e == "/");
num leftOp = calc[pos - 1];
num rightOp = calc[pos + 1];
switch (calc[pos]) {
case "*":
result = leftOp * rightOp;
break;
case "/":
result = leftOp / rightOp;
break;
}
calc.removeAt(pos);
calc.removeAt(pos);
calc[pos - 1] = result;
}
// Then After calculated "*" and "/" perform calculate on "+" and "-"
while (calc.length > 1) {
final pos = calc.indexWhere((e) => e == "-" || e == "+");
num leftOp = calc[pos - 1];
num rightOp = calc[pos + 1];
switch (calc[pos]) {
case "-":
result = leftOp - rightOp;
break;
case "+":
result = leftOp + rightOp;
break;
}
calc.removeAt(pos);
calc.removeAt(pos);
calc[pos - 1] = result;
}
expect(calc[0], correctResult);
});
}
this might not clean but this is what I founded that work
Related
Given:
A constant original array of string (~5k elements)
[
"595(###)###-###",
"974-####-####",
"262-#####-####",
"40-##-###-####",
"381-##-###-####",
...
]
The #-sign means "any digit". All # signs are located only after digits part, but can contain (), space or - sign
a user-typed string that could be like one of these
[
"1 (23"
"7 950 745 88 15",
"7 (950) 745-88-15",
"7 (950) 745 88-15",
"79507458815"
]
I need to find the most suitable mask in array (1) for given string (2).
The solution must fit in O(log n) in CPU, and, O(n^2) in memory.
My idea of suitability is based on Damerau–Levenshtein distance, but it punishes for every difference with #-sign, although it shouldn't.
I tried fuzzy search and BK-tree, but it works way too slow, takes about 100 ms to compute.
The answer was to use so-called Patricia tree
the final structure (JSON) is
{
"7": {
"12": {
"$value": "712###########",
},
"13": {
"4": {
...
}
},
"95#": {
"$value": "795###########",
},
"maxPrefixLength": "3",
...
},
"maxPrefixLength": "1",
...
}
The algorithm is (JS)
const getMaskedKeys = (obj: any) =>
Object.keys(obj).filter((e) => e.includes("#"));
const findValues = (node: TrieNode) => {
let currentNode = node;
const values: string[] = [];
while (currentNode) {
values.push(currentNode.$value);
currentNode = currentNode["#"];
}
return values;
};
const getObjectKeyByPath = (obj: any, path: string[]) => {
let result = obj;
for (const p of path) {
result = result[p];
}
return result;
};
export function createMaskTree(maskRows: string[]) {
const uniqueRows = [...new Set(maskRows)];
const masks = uniqueRows.map((mask, i) => {
const key = mask.replace(/[ +()\-]/g, "");
return [key, mask];
});
masks.sort((a, b) => (a[0] > b[0] ? 1 : -1));
const trie = Trie.create({
wildcard: "#",
});
masks.forEach(([key, mask]) => {
trie.insert(key, mask);
});
optimize(trie.tree);
return trie.tree as TrieNode;
}
export function searchMask(
cleanValue: string,
root: TrieNode,
debug = false
): string[] {
let matches: string[] = [];
let path: string[] = [];
let key = cleanValue;
const q: TrieNode[] = [root];
while (q.length) {
const currentNode = q.shift()!;
if (debug) {
console.log(
"Search Iteration. Key:",
key,
"Path:",
path,
"level:",
path.length
);
}
let l = currentNode.maxPrefixLength || key.length;
// let l = key.length;
let isEmpty = true;
// Search for existing prefixes and recursively descend
while (l--) {
const prefix = key.substring(0, l + 1);
if (debug) {
console.log("prefix=", prefix, "path=", path);
}
if (currentNode[prefix]) {
isEmpty = false;
path.push(prefix);
if (debug) {
console.log(prefix, "found in tree! current path:", path);
}
q.push(currentNode[prefix]);
const suffix = key.substring(l + 1);
key = suffix;
}
}
if (isEmpty) {
let l = currentNode.maxPrefixLength || key.length;
while (l--) {
const prefix = key.substring(0, l) + "#";
if (debug) console.log(" mask prefix=", prefix);
if (currentNode[prefix] && currentNode[prefix].$value) {
matches.push(...findValues(currentNode[prefix]));
}
}
}
}
if (!matches.length) {
if (debug)
console.log(
"No matches found without mask. Trying again with mask only!"
);
const last = path.pop();
key = last + key;
let currentNode: TrieNode = root;
let isRunning = true;
while (isRunning) {
currentNode = getObjectKeyByPath(root, path);
const keys = getMaskedKeys(currentNode);
if (debug) {
console.log(
"Mask search Iteration. Key:",
key,
"Path:",
path,
"level:",
path.length,
"currentNode keys:",
keys
);
}
let l = currentNode.maxPrefixLength || key.length;
while (l--) {
const prefix = key.substring(0, l) + "#";
if (debug) console.log(" mask prefix=", prefix);
if (currentNode[prefix] && currentNode[prefix].$value) {
matches.push(...findValues(currentNode[prefix]));
}
}
let pathPart = path.pop();
key = pathPart + key;
if (currentNode === root && !path.length) {
isRunning = false;
}
}
}
return matches;
}
I have a script that works mostly the way want. It looks at a cell then compares that to a column in another tab, finds the like items and returns that, and creates a dropdown on the cell. This moves down the column until it reaches the end. The problem is that it continues past the last row for about 20 rows. The starting row is row24.
function getInventoryItems() {
var jobSummaryInventoryItems = jobSummary.getRange(24, 8, jobSummary.getLastRow(), 1);
var jobSummaryInventoryItemsValues = jobSummaryInventoryItems.getValues();
var inventoryItems = inventory.getRange(4, 3, inventory.getLastRow(), 1);
var inventoryItemsValues = inventoryItems.getValues();
jobSummary.getRange(24, 8, jobSummary.getLastRow(), 1).setDataValidation(null);
for (z = 0; z < jobSummaryInventoryItemsValues.length; z++) {
if (jobSummaryInventoryItemsValues[z].toString().length > 1) {
var listOfInventory = [];
for (i = 0; i < inventoryItems.getLastRow() - 4; i++) {
if (inventoryItemsValues[i].toString() == jobSummaryInventoryItemsValues[z]) {
break;
}
var w = jobSummaryInventoryItemsValues[z];
if (inventoryItemsValues[i].toString().includes(jobSummaryInventoryItemsValues[z])) {
listOfInventory.push(inventoryItemsValues[i].toString());
}
}
}
if (listOfInventory.length > 0) {
var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(listOfInventory).build();
jobSummary.getRange(z + 24, 8).setDataValidation(rangeRule);
}
}
Get Inventory Items
function getInventoryItems() {
const ss = SpreadsheetApp.getActive();
const jobSummary = ss.getSheetByName('Job Summary');
const inventory = ss.getSheetByName('Inventory');
const jobSummaryInventoryItems = jobSummary.getRange(24, 8, jobSummary.getLastRow() - 23, 1);
const jobSummaryInventoryItemsValues = jobSummaryInventoryItems.getValues();
const inventoryItems = inventory.getRange(4, 3, inventory.getLastRow() - 3, 1);
const inventoryItemsValues = inventoryItems.getValues();
jobSummary.getRange(24, 8, jobSummary.getLastRow() -23, 1).setDataValidation(null);
for (z = 0; z < jobSummaryInventoryItemsValues.length; z++) {
if (jobSummaryInventoryItemsValues[z].toString().length > 1) {
let listOfInventory = [];
for (i = 0; i < inventoryItems.length; i++) {
if (inventoryItemsValues[i].toString() == jobSummaryInventoryItemsValues[z]) {
break;
}
let w = jobSummaryInventoryItemsValues[z];
if (inventoryItemsValues[i].toString().includes(jobSummaryInventoryItemsValues[z])) {
listOfInventory.push(inventoryItemsValues[i].toString());
}
}
}
if (listOfInventory.length > 0) {
let rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(listOfInventory).build();
jobSummary.getRange(z + 24, 8).setDataValidation(rangeRule);
}
}
}
Sheet.getRange(row,column,number of rows, number of columns)
In my Android app, I am trying to sort Bus route tags in order 1, 2, 3..etc.
For that I am using this
Collections.sort(directions, Comparator { lhs, rhs ->
var obj1 = lhs.short_names.firstOrNull() ?: ""
var obj2 = rhs.short_names.firstOrNull() ?: ""
if (obj1 === obj2) {
obj1 = lhs.headsigns.firstOrNull() ?: ""
obj2 = rhs.headsigns.firstOrNull() ?: ""
if (obj1 === obj2) {
return#Comparator 0
}
obj1.compareTo(obj2)
} else {
obj1.compareTo(obj2)
}
The issue I am having is this sorts them, but will run into the issue of
1, 2, 3, 30, 31, 4, 5
How should I change this to get the correct ordering.
If you need just a simple number comparison you can do it like that.
directions.sortWith(Comparator { lhs, rhs ->
val i1 = lhs.toInt()
val i2 = rhs.toInt()
when {
i1 < i2 -> -1
i1 > i2 -> 1
else -> 0
}
})
As hotkey pointed out the code above can be replaced with almost identical implementation that looks much simplier.
directions.sortBy { it.toInt() }
The general version of this algorithm is called alphanum sorting and described in details here. I made a Kotlin port of this algorithm, which you can use. It's more complicated than what you need, but it will solve your problem.
class AlphanumComparator : Comparator<String> {
override fun compare(s1: String, s2: String): Int {
var thisMarker = 0
var thatMarker = 0
val s1Length = s1.length
val s2Length = s2.length
while (thisMarker < s1Length && thatMarker < s2Length) {
val thisChunk = getChunk(s1, s1Length, thisMarker)
thisMarker += thisChunk.length
val thatChunk = getChunk(s2, s2Length, thatMarker)
thatMarker += thatChunk.length
// If both chunks contain numeric characters, sort them numerically.
var result: Int
if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
// Simple chunk comparison by length.
val thisChunkLength = thisChunk.length
result = thisChunkLength - thatChunk.length
// If equal, the first different number counts.
if (result == 0) {
for (i in 0..thisChunkLength - 1) {
result = thisChunk[i] - thatChunk[i]
if (result != 0) {
return result
}
}
}
} else {
result = thisChunk.compareTo(thatChunk)
}
if (result != 0) {
return result
}
}
return s1Length - s2Length
}
private fun getChunk(string: String, length: Int, marker: Int): String {
var current = marker
val chunk = StringBuilder()
var c = string[current]
chunk.append(c)
current++
if (isDigit(c)) {
while (current < length) {
c = string[current]
if (!isDigit(c)) {
break
}
chunk.append(c)
current++
}
} else {
while (current < length) {
c = string[current]
if (isDigit(c)) {
break
}
chunk.append(c)
current++
}
}
return chunk.toString()
}
private fun isDigit(ch: Char): Boolean {
return '0' <= ch && ch <= '9'
}
}
To use this Comparator just call
directions.sortWith(AlphanumComparator())
If you don't need it to be coded in Kotlin you can just take an original Java version on Dave Koelle's page. And the Kotlin version of the algorithm can be also found on GitHub.
I wrote a small function that splits a number to commas but I have to run over the number too many times. Can you sugest me a better way to do this?
public static function getCommaString(value:Number):String {
var stringValue:String = value.toString();
if (stringValue.length <= 3) {
return stringValue;
}
var i:int = stringValue.length % 3;
if (i == 0) {
i = 3;
}
for (; i < stringValue.length; i += 4 ) {
var part1:String = stringValue.substr(0, i);
var part2:String = stringValue.substr(i, stringValue.length);
stringValue = part1.concat(",", part2);
}
return stringValue;
}
I put together a testing class that compares your solution and others, including a solution from this blog post and solutions from this related StackExchange question and formatted them in a consistent way for easy comparison:
package
{
public class CommaNumberSolutions
{
public static function commaify( input:Number ):String
{
var split:Array = input.toString().split( '.' ),
front:String = split[0],
back:String = ( split.length > 1 ) ? "." + split[1] : null,
n:int = input < 0 ? 2 : 1,
commas:int = Math.floor( (front.length - n) / 3 ),
i:int = 1;
for ( ; i <= commas; i++ )
{
n = front.length - (3 * i + i - 1);
front = front.slice( 0, n ) + "," + front.slice( n );
}
if ( back )
return front + back;
else
return front;
}
public static function getCommaString( input:Number ):String
{
var s:String = input.toString();
if ( s.length <= 3 )
return s;
var i:int = s.length % 3;
if ( i == 0 )
i = 3;
for ( ; i < s.length; i += 4 )
{
var part1:String = s.substr(0, i);
var part2:String = s.substr(i, s.length);
s = part1.concat(",", part2);
}
return s;
}
public static function formatNumber( input:Number ):String
{
var s:String = input.toString()
var result:String = ''
while ( s.length > 3 )
{
var chunk:String = s.substr(-3)
s = s.substr(0, s.length - 3)
result = ',' + chunk + result
}
if ( s.length > 0 )
result = s + result
return result
}
public static function commaCoder( input:Number ):String
{
var s:String = "";
var len:Number = input.toString().length;
for ( var i:int = 0; i < len; i++ )
{
if ( (len-i) % 3 == 0 && i != 0)
s += ",";
s += input.toString().charAt(i);
}
return s;
}
public static function regex1( input:Number ):String
{
return input.toString().replace( /-{0,1}(\d)(?=(\d\d\d)+$)/g, "$1," );
}
public static function regex2( input:Number ):String
{
return input.toString().replace( /-{0,1}\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,")
}
public static function addCommas( input:Number ):String
{
var negative:String = "";
if ( input < 0 )
{
negative = "-";
input = Math.abs(input);
}
var s:String = input.toString();
var results:Array = s.split(/\./);
s = results[0];
if ( s.length > 3 )
{
var mod:Number = s.length % 3;
var output:String = s.substr(0, mod);
for ( var i:Number = mod; i < s.length; i += 3 )
{
output += ((mod == 0 && i == 0) ? "" : ",") + s.substr(i, 3);
}
if ( results.length > 1 )
{
if ( results[1].length == 1 )
return negative + output + "." + results[1] + "0";
else
return negative + output + "." + results[1];
}
else
return negative + output;
}
if ( results.length > 1 )
{
if ( results[1].length == 1 )
return negative + s + "." + results[1] + "0";
else
return negative + s + "." + results[1];
}
else
return negative + s;
}
}
}
You can see a more detailed analysis at my other answer but you can compare the compactness of each solution and weigh that against their accuracy and performance, however for the sake of brevity this solution is the most accurate and performant (though not the most compact):
public function commaify( input:Number ):String
{
var split:Array = input.toString().split( '.' ),
front:String = split[0],
back:String = ( split.length > 1 ) ? "." + split[1] : null,
n:int = input < 0 ? 2 : 1,
commas:int = Math.floor( (front.length - n) / 3 ),
i:int = 1;
for ( ; i <= commas; i++ )
{
n = front.length - (3 * i + i - 1);
front = front.slice( 0, n ) + "," + front.slice( n );
}
if ( back )
return front + back;
else
return front;
}
I've written software in the past that uses a stack to check for balanced equations, but now I'm asked to write a similar algorithm recursively to check for properly nested brackets and parenthesis.
Good examples: () [] ()
([]()[])
Bad examples: ( (] ([)]
Suppose my function is called: isBalanced.
Should each pass evaluate a smaller substring (until reaching a base case of 2 left)? Or, should I always evaluate the full string and move indices inward?
First, to your original question, just be aware that if you're working with very long strings, you don't want to be making exact copies minus a single letter each time you make a function call. So you should favor using indexes or verify that your language of choice isn't making copies behind the scenes.
Second, I have an issue with all the answers here that are using a stack data structure. I think the point of your assignment is for you to understand that with recursion your function calls create a stack. You don't need to use a stack data structure to hold your parentheses because each recursive call is a new entry on an implicit stack.
I'll demonstrate with a C program that matches ( and ). Adding the other types like [ and ] is an exercise for the reader. All I maintain in the function is my position in the string (passed as a pointer) because the recursion is my stack.
/* Search a string for matching parentheses. If the parentheses match, returns a
* pointer that addresses the nul terminator at the end of the string. If they
* don't match, the pointer addresses the first character that doesn't match.
*/
const char *match(const char *str)
{
if( *str == '\0' || *str == ')' ) { return str; }
if( *str == '(' )
{
const char *closer = match(++str);
if( *closer == ')' )
{
return match(++closer);
}
return str - 1;
}
return match(++str);
}
Tested with this code:
const char *test[] = {
"()", "(", ")", "", "(()))", "(((())))", "()()(()())",
"(() ( hi))) (())()(((( ))))", "abcd"
};
for( index = 0; index < sizeof(test) / sizeof(test[0]); ++index ) {
const char *result = match(test[index]);
printf("%s:\t", test[index]);
*result == '\0' ? printf("Good!\n") :
printf("Bad # char %d\n", result - test[index] + 1);
}
Output:
(): Good!
(: Bad # char 1
): Bad # char 1
: Good!
(())): Bad # char 5
(((()))): Good!
()()(()()): Good!
(() ( hi))) (())()(((( )))): Bad # char 11
abcd: Good!
There are many ways to do this, but the simplest algorithm is to simply process forward left to right, passing the stack as a parameter
FUNCTION isBalanced(String input, String stack) : boolean
IF isEmpty(input)
RETURN isEmpty(stack)
ELSE IF isOpen(firstChar(input))
RETURN isBalanced(allButFirst(input), stack + firstChar(input))
ELSE IF isClose(firstChar(input))
RETURN NOT isEmpty(stack) AND isMatching(firstChar(input), lastChar(stack))
AND isBalanced(allButFirst(input), allButLast(stack))
ELSE
ERROR "Invalid character"
Here it is implemented in Java. Note that I've switched it now so that the stack pushes in front instead of at the back of the string, for convenience. I've also modified it so that it just skips non-parenthesis symbols instead of reporting it as an error.
static String open = "([<{";
static String close = ")]>}";
static boolean isOpen(char ch) {
return open.indexOf(ch) != -1;
}
static boolean isClose(char ch) {
return close.indexOf(ch) != -1;
}
static boolean isMatching(char chOpen, char chClose) {
return open.indexOf(chOpen) == close.indexOf(chClose);
}
static boolean isBalanced(String input, String stack) {
return
input.isEmpty() ?
stack.isEmpty()
: isOpen(input.charAt(0)) ?
isBalanced(input.substring(1), input.charAt(0) + stack)
: isClose(input.charAt(0)) ?
!stack.isEmpty() && isMatching(stack.charAt(0), input.charAt(0))
&& isBalanced(input.substring(1), stack.substring(1))
: isBalanced(input.substring(1), stack);
}
Test harness:
String[] tests = {
"()[]<>{}",
"(<",
"]}",
"()<",
"(][)",
"{(X)[XY]}",
};
for (String s : tests) {
System.out.println(s + " = " + isBalanced(s, ""));
}
Output:
()[]<>{} = true
(< = false
]} = false
()< = false
(][) = false
{(X)[XY]} = true
The idea is to keep a list of the opened brackets, and if you find a closing brackt, check if it closes the last opened:
If those brackets match, then remove the last opened from the list of openedBrackets and continue to check recursively on the rest of the string
Else you have found a brackets that close a nerver opened once, so it is not balanced.
When the string is finally empty, if the list of brackes is empty too (so all the brackes has been closed) return true, else false
ALGORITHM (in Java):
public static boolean isBalanced(final String str1, final LinkedList<Character> openedBrackets, final Map<Character, Character> closeToOpen) {
if ((str1 == null) || str1.isEmpty()) {
return openedBrackets.isEmpty();
} else if (closeToOpen.containsValue(str1.charAt(0))) {
openedBrackets.add(str1.charAt(0));
return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
} else if (closeToOpen.containsKey(str1.charAt(0))) {
if (openedBrackets.getLast() == closeToOpen.get(str1.charAt(0))) {
openedBrackets.removeLast();
return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
} else {
return false;
}
} else {
return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
}
}
TEST:
public static void main(final String[] args) {
final Map<Character, Character> closeToOpen = new HashMap<Character, Character>();
closeToOpen.put('}', '{');
closeToOpen.put(']', '[');
closeToOpen.put(')', '(');
closeToOpen.put('>', '<');
final String[] testSet = new String[] { "abcdefksdhgs", "[{aaa<bb>dd}]<232>", "[ff{<gg}]<ttt>", "{<}>" };
for (final String test : testSet) {
System.out.println(test + " -> " + isBalanced(test, new LinkedList<Character>(), closeToOpen));
}
}
OUTPUT:
abcdefksdhgs -> true
[{aaa<bb>dd}]<232> -> true
[ff{<gg}]<ttt> -> false
{<}> -> false
Note that i have imported the following classes:
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
public static boolean isBalanced(String str) {
if (str.length() == 0) {
return true;
}
if (str.contains("()")) {
return isBalanced(str.replaceFirst("\\(\\)", ""));
}
if (str.contains("[]")) {
return isBalanced(str.replaceFirst("\\[\\]", ""));
}
if (str.contains("{}")) {
return isBalanced(str.replaceFirst("\\{\\}", ""));
} else {
return false;
}
}
Balanced Parenthesis (JS)
The more intuitive solution is to use stack like so:
function isBalanced(str) {
const parentesis = {
'(': ')',
'[': ']',
'{': '}',
};
const closing = Object.values(parentesis);
const stack = [];
for (let char of str) {
if (parentesis[char]) {
stack.push(parentesis[char]);
} else if (closing.includes(char) && char !== stack.pop()) {
return false;
}
}
return !stack.length;
}
console.log(isBalanced('{[()]}')); // true
console.log(isBalanced('{[(]]}')); // false
console.log(isBalanced('([()]')); // false
And using recursive function (without using stack), might look something like so:
function isBalanced(str) {
const parenthesis = {
'(': ')',
'[': ']',
'{': '}',
};
if (!str.length) {
return true;
}
for (let i = 0; i < str.length; i++) {
const char = str[i];
if (parenthesis[char]) {
for (let j = str.length - 1; j >= i; j--) {
const _char = str[j];
if (parenthesis[_char]) {
return false;
} else if (_char === parenthesis[char]) {
return isBalanced(str.substring(i + 1, j));
}
}
} else if (Object.values(parenthesis).includes(char)) {
return false;
}
}
return true;
}
console.log(isBalanced('{[()]}')); // true
console.log(isBalanced('{[(]]}')); // false
console.log(isBalanced('([()]')); // false
* As #Adrian mention, you can also use stack in the recursive function without the need of looking backwards
It doesn't really matter from a logical point of view -- if you keep a stack of all currently un-balanced parens that you pass to each step of the recursion, you'll never need to look backwards, so it doesn't matter if you cut up the string on each recursive call, or just increment an index and only look at the current first character.
In most programming languages, which have non-mutable strings, it's probably more expensive (performance-wise) to shorten the string than it is to pass a slightly larger string on the stack. On the other hand, in a language like C, you could just increment a pointer within the char array. I guess it's pretty language-dependent which of these two approaches is more 'efficient'. They're both equivalent from a conceptual point of view.
In the Scala programming language, I would do it like this:
def balance(chars: List[Char]): Boolean = {
def process(chars: List[Char], myStack: Stack[Char]): Boolean =
if (chars.isEmpty) myStack.isEmpty
else {
chars.head match {
case '(' => process(chars.tail, myStack.push(chars.head))
case ')' => if (myStack.contains('(')) process(chars.tail, myStack.pop)
else false
case '[' => process(chars.tail, myStack.push(chars.head))
case ']' => {
if (myStack.contains('[')) process(chars.tail, myStack.pop) else false
}
case _ => process(chars.tail, myStack)
}
}
val balancingAuxStack = new Stack[Char]
process(chars, balancingAuxStack)
}
Please edit to make it perfect.
I was only suggesting a conversion in Scala.
I would say this depends on your design. You could either use two counters or stack with two different symbols or you can handle it using recursion, the difference is in design approach.
func evalExpression(inStringArray:[String])-> Bool{
var status = false
var inStringArray = inStringArray
if inStringArray.count == 0 {
return true
}
// determine the complimentary bracket.
var complimentaryChar = ""
if (inStringArray.first == "(" || inStringArray.first == "[" || inStringArray.first == "{"){
switch inStringArray.first! {
case "(":
complimentaryChar = ")"
break
case "[":
complimentaryChar = "]"
break
case "{":
complimentaryChar = "}"
break
default:
break
}
}else{
return false
}
// find the complimentary character index in the input array.
var index = 0
var subArray = [String]()
for i in 0..<inStringArray.count{
if inStringArray[i] == complimentaryChar {
index = i
}
}
// if no complimetary bracket is found,so return false.
if index == 0{
return false
}
// create a new sub array for evaluating the brackets.
for i in 0...index{
subArray.append(inStringArray[i])
}
subArray.removeFirst()
subArray.removeLast()
if evalExpression(inStringArray: subArray){
// if part of the expression evaluates to true continue with the rest.
for _ in 0...index{
inStringArray.removeFirst()
}
status = evalExpression(inStringArray: inStringArray)
}
return status
}
PHP Solution to check balanced parentheses
<?php
/**
* #param string $inputString
*/
function isBalanced($inputString)
{
if (0 == strlen($inputString)) {
echo 'String length should be greater than 0';
exit;
}
$stack = array();
for ($i = 0; $i < strlen($inputString); $i++) {
$char = $inputString[$i];
if ($char === '(' || $char === '{' || $char === '[') {
array_push($stack, $char);
}
if ($char === ')' || $char === '}' || $char === ']') {
$matchablePairBraces = array_pop($stack);
$isMatchingPair = isMatchingPair($char, $matchablePairBraces);
if (!$isMatchingPair) {
echo "$inputString is NOT Balanced." . PHP_EOL;
exit;
}
}
}
echo "$inputString is Balanced." . PHP_EOL;
}
/**
* #param string $char1
* #param string $char2
* #return bool
*/
function isMatchingPair($char1, $char2)
{
if ($char1 === ')' && $char2 === '(') {
return true;
}
if ($char1 === '}' && $char2 === '{') {
return true;
}
if ($char1 === ']' && $char2 === '[') {
return true;
}
return false;
}
$inputString = '{ Swatantra (() {} ()) Kumar }';
isBalanced($inputString);
?>
It should be a simple use of stack ..
private string tokens = "{([<})]>";
Stack<char> stack = new Stack<char>();
public bool IsExpressionVaild(string exp)
{
int mid = (tokens.Length / 2) ;
for (int i = 0; i < exp.Length; i++)
{
int index = tokens.IndexOf(exp[i]);
if (-1 == index) { continue; }
if(index<mid ) stack .Push(exp[i]);
else
{
if (stack.Pop() != tokens[index - mid]) { return false; }
}
}
return true;
}
#indiv's answer is nice and enough to solve the parentheses grammar problems. If you want to use stack or do not want to use recursive method you can look at the python script on github. It is simple and fast.
BRACKET_ROUND_OPEN = '('
BRACKET_ROUND__CLOSE = ')'
BRACKET_CURLY_OPEN = '{'
BRACKET_CURLY_CLOSE = '}'
BRACKET_SQUARE_OPEN = '['
BRACKET_SQUARE_CLOSE = ']'
TUPLE_OPEN_CLOSE = [(BRACKET_ROUND_OPEN,BRACKET_ROUND__CLOSE),
(BRACKET_CURLY_OPEN,BRACKET_CURLY_CLOSE),
(BRACKET_SQUARE_OPEN,BRACKET_SQUARE_CLOSE)]
BRACKET_LIST = [BRACKET_ROUND_OPEN,BRACKET_ROUND__CLOSE,BRACKET_CURLY_OPEN,BRACKET_CURLY_CLOSE,BRACKET_SQUARE_OPEN,BRACKET_SQUARE_CLOSE]
def balanced_parentheses(expression):
stack = list()
left = expression[0]
for exp in expression:
if exp not in BRACKET_LIST:
continue
skip = False
for bracket_couple in TUPLE_OPEN_CLOSE:
if exp != bracket_couple[0] and exp != bracket_couple[1]:
continue
if left == bracket_couple[0] and exp == bracket_couple[1]:
if len(stack) == 0:
return False
stack.pop()
skip = True
left = ''
if len(stack) > 0:
left = stack[len(stack) - 1]
if not skip:
left = exp
stack.append(exp)
return len(stack) == 0
if __name__ == '__main__':
print(balanced_parentheses('(()())({})[]'))#True
print(balanced_parentheses('((balanced)(parentheses))({})[]'))#True
print(balanced_parentheses('(()())())'))#False