I'm trying to make a calculator app, and I need to be able to get the last value after someone presses an operator (+,*,-,/) after the second time (the first value is saved with no issues since it's the only number on the screen).
So if the top of the screen has something like (222 * 3333 / 12), I need to get 12. Once I learn how to do this, I can figure out how to save the previous number/sum, then do calculations on the next number (I haven't made that part yet though).
I know this is a janky way of doing things, and any suggestions are appreciated.
So I can grab this number if I use substringAfterLast() and insert an operator there, however, if mix things up and use multiple operators (like 222 * 3333 / 12), my y variable (see below) just shows "222 * 3333 / 12" instead of 12.
How can I use multiple delimiters for substring?
Here's my code by the way (forgive me)
multiplybutton.setOnClickListener {
var x = numbersEntered.toString()
var y = ""
//creates an array that holds the operators so it can be easily filtered out
val operators = arrayOf<Char>('*','/','+','-')
//prevents app from crashing by saving the last value before the operator is added, allowing us to create infinite number of operations
if (x.any(operators :: contains)){
// x.split(operators.toString())
y = x.substringAfterLast('*') // can't use my operator character array here? why? how do I iterate through it?
Toast.makeText(this, y.toString(), Toast.LENGTH_SHORT).show()
// previousvalue = y.toInt()
} else {
previousvalue = x.toInt()
}
numbersEntered.append("*")
numbersEnteredBox.setText(numbersEntered.toString())
isMultiply = true;
Toast.makeText(this, previousvalue.toString(), Toast.LENGTH_SHORT).show()
}
edit: ignore italics plz, not sure what went wrong
sorry, maybe I not fully understand what you want to do but you can use split function to get last number from string like this 222 * 3333 / 12:
println("222 * 3333 / 12".split('+', '-', '*', '/').last().trim().toInt())
// prints 12
Use split with a regular expression
Using a regular expression gives you a great deal of control over how the string is split. In your case, anything that isn't a numeric digit is probably a delimiter. Regex has a built-in character class, denoted by \D, that will match any character that isn't a digit.
val pattern = Regex("""\D+""") // matches one or more non-digit characters
"1 * 2 / 3".split(pattern).last() // returns "3"
Equally, you could create your own character class, using [], to be more specific about which characters you want to use as delimiters:
val pattern = Regex("""\s*[-\+*]\s*""") // matches -\+*, and any spaces around them
"1 * 2 / 3".split(pattern).last() // returns "3"
Related
I am quite new to all things Android and Kotlin. I am currently working with an Android app from Punch Through:
(Blog: https://punchthrough.com/android-ble-guide/)
(GitHub: https://github.com/PunchThrough/ble-starter-android)
The app connects with a BLE peripheral and allows the user to enter text to send to the peripheral via UART.
I am struggling interpreting what the following code means / does:
with(hexField.text.toString()) {
if (isNotBlank() && isNotEmpty()) {
val bytes = hexToBytes()
ConnectionManager.writeCharacteristic(device, characteristic, bytes)
}
}
Where hexField.text.toString() is the text entered in the EditText field by the user,
and
where hexToBytes() is defined as:
private fun String.hexToBytes() =
this.chunked(2).map { it.toUpperCase(Locale.US).toInt(16).toByte() }.toByteArray()
I have tried this a few times, always entering “111” and have am using Timber() to output the result of bytes. This result varies every time, for example:
[B#2acf801
[B#476814a
[B#e9a70e5
[B#10172a0
So, I assume that only the first three characters are relevant, and somehow there is no end of line / string information.
So perhaps I am only interested in: [B#.......
B# = 0x 5B 42 40
Hex: 5B4240
Dec: 5980736
Bin: 10110110100001001000000
So then I try (and fail) to interpret / breakdown what this code might be doing.
The first thing I struggle with is understanding the order of operation.
Here's my guess....
Given EditText entry, in this case I entered "111"
First:
this.chunked(2)
would produce something like:
"11 and "01"
Second, for each of the two items ("11 and "01"):
it.toUpperCase(Locale.US).toInt(16).toByte()
would produce byte values:
17 and 1
Third:
.map .toByteArray()
Would produce something like:
[1,7,1]
or
[0x01, 0x07, 0x1]
or
[0x0x31, 0x37, 0x31]
So, as you can see, I am getting lost in this!
Can anyone help me deconstruct this code?
Thanks in advance
Garrett
I have tried this a few times, always entering “111” and have am using Timber() to output the result of bytes. This result varies every time
The output when you try to print a ByteArray (or any array on the JVM) doesn't show the contents of the array, but its type and address in memory. This is why you don't get the same result every time.
In order to print an array's contents, use theArray.contentToString() (instead of plain interpolation or .toString()).
Regarding the interpretation of the code, you almost got it right, but there are a few mistakes here and there.
this.chunked(2) on the string "111" would return a list of 2 strings: ["11", "1"] - there is no padding here, just the plain strings with max size of 2.
Then, map takes each of those elements individually and applies the transformation it.toUpperCase(Locale.US).toInt(16).toByte(). This one makes the string uppercase (doesn't change anything for the 1s), and then converts the string into an integer by interpreting it in base 16, and then truncates this integer to a single byte. This part you got right, it transforms "11" into 17 and "1" into 1, but the map {...} operation transforms the list ["11", "1"] into [17, 1], it doesn't take the digits of 17 individually.
Now toByteArray() just converts the List ([17, 1]) into a byte array of the same values, so it's still [17, 1].
Could anyone explain to me why this code works:
if (questionList[currentIndex].answer == inputAnswer) {
correctAnswers += 1*100/questionList.size
percentage.text = "Правильно: $correctAnswers%"
and this one doesn't:
if (questionList[currentIndex].answer == inputAnswer) {
correctAnswers += 1/questionList.size*100
percentage.text = "Правильно: $correctAnswers%"
When I click a button, set up with the first bit of code, everything works fine and my textView gets updated, but when I change the order of operations, nothing happens (textView.text doesn't change it's value).
Am I missing something?
Thank you in advance!
When you do math with integers, fraction components are not preserved. Suppose the size of the question list is 10.
In your first block of code, you have
1 * 100 / 10
Operations are done from left to right, so after the first multiplication, you have
100 / 10
and that resolves to 10.
Now with your second block of code you have
1 / 10 * 100
The first division with floating point numbers would be 0.1, but with integers, since the fraction is not preserved, it evaluates to 0.
0 * 100
which resolves to 0. So it will always result in zero if the dividend is smaller than the divisor.
If you really want to present fractional numbers, you should use floating point numbers, and if you want the result to be an Int, use roundToInt() on the result. If you just use toInt(), it will just drop the fraction rather than rounding to the nearest integer.
I need an idea on doing this. I'm not good at math.
Maybe it have build in function which i haven't found yet.
I have an array which consists of 2048 data.
I need to get on 250 value out of this.
I'm thinking of
2048/250 = 8.19
which means, I take value on each increment of 8 position in an array.
Is there a function to do this?
Not that I'm aware of, I think the problem is to balance iterations and the randomness of the sampling.
So the naive approach
dataSet.indexedMapNotNull { i, data ->
if (i % 8 == 0) data else null
}
That would run through all the array, so you only need 250 iterations, not dataSet.size iterations. So what about if we iterate 250 times and for each of those we take the 8th times of it
val sample = mutableListOf<DataType>()
for (i in 1..250) {
val positionInDataSet = (i * 8) - 1 //minus one adjust the index for the size
val case = dataSet[positionInDataSet]
sample.add(case)
}
Another alternative would be to simply use copy methods from collections, but the problem is you lose your sampling
dataSet.subArray(0, 250)
Sub-array didn't sample the data in a pseudo-random way but only got the first 250 and that would be biased. The upside is usually array copies methods are a log of N.
Another option would be to randomize things even more by not getting data each 8 but a random position until we hit our desired sample size.
val sample = mutableSetOf<DataType>()
while (sample.size != 250) {
val randomPosition = Random.nextInt(0, dataSet.size)
val randomSelection = dataSet[randomPosition]
sample.add(randomeSelection)
}
Here we use a set, because a Set guarantee unique elements, so you have completely random 250 elements from your data set. The problem with this is that randomness on the position could make the same randomPosition more than once, so you iterate on the data set more than 250 times, this could even be factorial which in larger data sets it would happen and is considered the lowest performance.
I want to group strings based on character.
For eg. I want to split following url in two groups
group 1 - /viewarticle/abd-fdj-gfg-to
group2 - 628882 (last string)
/viewarticle/abd-fdj-gfg-to-628882
I tried this " -(?!.*-) " but it is not working.
I have to use only regex not split function.
Any help would be appreciated.
You can simply use groups () with .*- to capture the first input and the rest as second so use:
(.*-)([a-zA-Z\\d]+)
Demo
val regex = "(.*-)([a-zA-Z\\d]+)".toRegex() // use only (\\d+) for digits
val matchResults = regex.find("/viewarticle/abd-fdj-gfg-to-628882")!!
val (link, id) = matchResults.destructured
println("Link: $link \nID: $id")
Details:
.*- : match anything till last -
[a-zA-Z\\d]+ : match 0 or more characters a-zA-Z or digits
You may try splitting using a lookbehind, e.g. split on:
(?<=-to)-
You could also make the lookbehind more specific:
(?<=abd-fdj-gfg-to)-
But this would only make sense if what precedes -to would always be the same.
Edit:
If you need to split on the last hyphen, then use the negative lookahead:
-(?!.*-)
I'm try to write a username field validator and one of the reqs is that the field must contain at least 2 numbers (more is ok, just no less). I thought I could do something like this, and the regex splits on the first number, but never on the second.
String[] arr = string.split("[0-9][0-9]");
return arr.length > 2;
Use cases:
Bob11
Bo1b1
11Bob
1Bob1
Below is my version, that has an extremely fast execution, can be easily updated to different criteria, and has a better readability (at least to me):
Regex
(\D*\d){2,}
Example
Bob11 - Match
Bo1b1 - Match
11Bob - Match
1Bob1 - Match
11235 - Match
Bobb - Does NOT Match
Bob1 - Does NOT Match
Bo1b - Does NOT Match
1Bob - Does NOT Match
Explanation
\D - non digit.
* - (quantifier) zero or more times.
\d - one digit.
(\D*\d) - encapsulate the combination above as a group.
{2,} - (quantifier) ensures that the group occurs at least 2 times, being able to occur more times.
(\D*\d){2,} - So, \D* non digit zero or infinite times, followed by a \d digit, this combination repeated {2,} two or infinite times.
Updating to different criteria
The ^ (start string anchor) and $ (end string anchor) can be included to ensure restriction, in case the criteria changes to be exact 2 or any other number.
This is an example that ensures no more, no less that 5 numbers anywhere in a string: ^(\D*\d){5}\D*$. The last \D is necessary to allow the string to end with a non digit, validating the regex if the criteria of five digits be satisfied.*
Try this:
.* matches everything (from 0 to n times)
[0-9] is number from 0-9
Pattern pattern = Pattern.compile("[0-9].*[0-9]");
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
return true;
}
And you can check regex in https://www.freeformatter.com/regex-tester.html
Remove all non numeric characters using regex and count the length
[^\d]*\d[^\d]*\d.* should be one way to go (there are several..)
[^\d]* Matches any character which is not a digit (zero to infinite times)
\d matches a single digit (once)
.* matches everything (zero to infinite times)
I use [^\d]* because .* is greedy and thus might match too much (depending on the language). Greedy behavior can be disabled by appending ?: .*?
You can test it at https://regex101.com/.
You do not need RegEx for this. I'm not sure what language you're using, but it is safe to assume that a String in your language is essentially a Char array. If that is the case, then get the count of digit characters in the Char array and compare if it is greater than 1.
For example, here is a C# example:
String username = Console.ReadLine();
if (username.Count(c => Char.IsDigit(c)) > 1) {
Console.WriteLine("The String contains 2 or more digits.");
} else {
Console.WriteLine("The String did not contain 2 or more digits.");
}
This would likely yield faster results too.
Use string.match(‘.*\d.*\d.*’);
It will look for one digit two times in a string.