I have a table which a column is a string with three characters, each character has a value 0 or 1. I'd like to select those rows according to the case.
I'd like to perform a query like that:
SELECT * FROM Item WHERE group_type LIKE ?
? can be 100 or 101 or 011 or 111 or 001. A combination with 0 and 1 in three characters.
I'm trying to query using LIKE
WhereCondition where = null;
switch (condition) {
case case1:
where = ItemDao.Properties.GroupType.like("1%");
break;
case case2:
where = ItemDao.Properties.GroupType.like("%1%");
break;
case case3:
where = ItemDao.Properties.GroupType.like("%1");
break;
}
List<Item> items = itemDao.queryBuilder().where(where).list();
case1 is returning everything that starts with 1 as expected.
case3 is returning everything that ends with 1 as expected.
case2 is returning everything! It doesn't metter the value in the beggining, middle or end. It's returning everything.
case1 and case3 are working fine. However, case2 isn't working. Is there any problem with that?
No. "%1%" is supposed to return everything where "1" occurs. It can be "100", "010" or "101", but not "000".
From the sqlite like clause reference page:
The percent sign represents zero, one, or multiple numbers or characters. The underscore represents a single number or character. These symbols can be used in combinations.
By saying %1% you are searching for elements that have at least one number 1, regardless where it may be. This is mostly because % meaning zero, one or multiple occurrences. This is further explained in that link by the following example:
WHERE SALARY LIKE '%200%'
Finds any values that have 200 in any position
So we can see that indeed you are getting the expected behavior.
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].
In my Android app we use couchbase lite database version 2.8.6
I run three database queries.
One item in where clause.
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE)))
In the result I see three items from database printed to a console. As expected. Format here ans below is id|timestamp|rating
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
e02d0eb3-6c9b-4942-b43c-a752eefc77a8|1630525956184|2147483647
I add and() condition to where() to get all items where type = 'type' AND rating < 1
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE))
.and(Expression.property("rating").lessThan(Expression.intValue(1))
)
Result is as expected as we search everything with rating < 1, third item is filtered out.
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
Finally, I want to see records where type = 'type' AND rating < 1 AND timestamp <= 1
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE))
.and(Expression.property("rating").lessThan(Expression.intValue(1))
.and(Expression.property("timestamp")).lessThanOrEqualTo (Expression.longValue(1))
)
)
And now the result is really strange as I receive three items form the database. And the third one has timestamp much greater than 1 put into the query.
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
e02d0eb3-6c9b-4942-b43c-a752eefc77a8|1630525956184|2147483647
Any ideas how to make it work with multiple and()? If I try to remove the second and() and keep the third one everything works as expected.
After deep investigations I found several problems in my code:
.and() should be called at the end of the "child" condition and not at the "parent" level.
For the conditions like this
val condition1 = Expression.property("type").equalTo(Expression.string(DOC_TYPE))
val condition2 = Expression.property("rating").lessThan(Expression.intValue(1))
val condition3 = Expression.property("timestamp")).lessThanOrEqualTo (Expression.longValue(1))
The correct way is
.where(condition1.and(
condition2.and(
condition3.and(
...
)
)
)
but NOT like I've tried
.where(condition1.and(condition2)
.and(condition3)
.and(...)
)
For the creation of the object I used a code that converts an object to Map<String, Any> before saving to couchbase. Everything seemed to be OK till I realized that Long was converted to Double.
The last point, I have much complicated queries and inside one of them I accidentally used .add() instead of .and(). No comments.
Hope this will help to somebody to save some time.
I would expect that the query would be as you did originally:
.where(condition1.and(condition2)
.and(condition3)
.and(...))
I think there is an additional parenthesis here that seems to be wrong:
.and(Expression.property("timestamp"))
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"
I'm working on a 3 track step sequencer, and the spinners for sample selection are causing me some trouble. The following code is executed when a saved pattern is loaded to set the correct samples.
for ((index, j) in spinners.withIndex()){
val item = loadingPattern[(48+index)]
Log.i("item", item.toString())
Log.i("int", item.toInt().toString)
j.setSelection(item.toInt())
}
The array "spinners" contains 3 spinners with 5 entries each. "loadingPattern" is a string that contains the pattern information. The last three characters are integers corresponding to the spinner position. When the spinner selections are as the following:
Spinner 1: Selected item index 0
Spinner 2: Selected item index 3
Spinner 3: Selected item index 4
The log "item" prints exactly these values. The log "int" however prints 48+index, so in this case 48, 50, 52. Since the toInt() function is also called on the value parsed to the .setSelection() function, this exception is triggered:
java.lang.ArrayIndexOutOfBoundsException: length=2; index=48
If anyone has an idea why this is happening, I would be very happy to know. Thank you all so much! I love this communtiy!
edit:
If the pattern is programmed like this:
typical pattern
The "patternString" is the following:
101010101010101010000000100000001000100010001000420
active steps are represented by 1, the others by 0. The last 3 digits are the spinner positions. Maybe this will help :)
Edit 2:
I just found this question: I have String with numbers when getting the char from string it shows '0'48 in kotlin. How to get the char alone in kotlin
And there they say that the ASCII value of 0 is 48. This means that toInt() probably returns the ASCII value of 0. But why is that and how can I get just the normal integer?
I found it out!
As stated in this article, the toInt() function only works for strings and indeed returns the ASCII value of chars. The correct way of doing this is using Character.getNumericValue().
I am now working on a calculator, and everything works fine except for decimal places.
The calculator contains 2 displays actually, one is called fakedisplay for actual operations, and one is called Display, for presenting the desired format, ie adding commas.
When pressing 12345.678, Display will follow fakedisplay and present as 12,345.678, but if i press 12345.009, the fakedisplay will work normally as 12345.009, but the Display stuck as 12,345 until 9 is pressed, and at that time it will show 12,345.009 normally.
However, it is strange that when the user presses 0, there is no response, and until pressing 9, 009 will then immediately append.
I know this arise from the parsing code, but based on this, how could I amend the following code? I really cannot think of any solution... Many thanks for all your advice!
one.setOnClickListener(new View.OnClickListener() {
if (str.length()<15) {
Fakedisplay.append("1");
}
DecimalFormat myFormatter1 = new DecimalFormat("###,###,###,###.#################");
String str1=Fakedisplay.getText().toString();
String stripped1 = Double.valueOf(str1).toString();
stripped1 = myFormatter1.format(Double.valueOf(stripped1));
if (stripped1.endsWith(".0"))
stripped1 = stripped1.substring(0, stripped1.length() - 2);
Display.setText(stripped1);
}
Probably the easiest solution is to not strip off the .0 in the code for every keystroke..
Instead, only strip off trailing zeros (assuming there's a decimal point in there of course) when the user calls for a result. Entering keys such as the digit keys 0 through 9, the decimal point ., or the sign-change key +/- (what I'll call the entry keys) are not generating a result so should not strip trailing zeros.
However, non-entry keys, such as when you press + or - or = on your calculator can freely modify the number.
That will give you a display of the digits being entered as the user enters them but will still strip off trailing zeros when necessary.
You can do that with a modification to your statement (and, as mentioned, only doing this when the user presses a non-entry key):
stripped1 = stripped1.replaceAll("(\\.[0-9]*[1-9])0+$","$1");
stripped1 = stripped1.replaceAll("\\.0$","");
The first statement removes all trailing zeros at the end of a decimal number (other than on if it's really an integer). The second takes care of that case.
No doubt I could make a single substitution if I gave it some more thought but that should be enough to get it functional.