java key pressed event off by one letter - java

this is the method I'm using to test this:
private void searchFieldKeyTyped(java.awt.event.KeyEvent evt) {
String query = searchField.getText();
System.out.println(query);
}
if i type one letter though, query contains an empty string
if i type another letter, query contains the single previous letter
so if i type "a", query is empty
If I type "ab", query contains "a"
If i type "abc", query contains "ab"
If I type "abcd", query contains "abc"
and so on.

As discussed in the comments, use KEY_RELEASED rather than KEY_PRESSED.

Related

why the element in my List<Integer> is type Character?

As shown in above picture, my method accepts `List includedDays, and I expect the element is of type Integer, but why in debug mode, I find that the element is of typeCharacter?
includeDays comes from the following code:
List<Integer> includedDays = getDowByTrmClassId(trmClassId);
and getDowByTrmClassId(trmClassId) is defined as:
List<Integer> getDowByTrmClassId(Integer trmClassId){
Session session = HibernateUtil.getCurrentSession();
String sql = " select DOW from TRM_CLASS_DOW cdow " +
"where (cdow.UPDATE_MODE is null or cdow.UPDATE_MODE <> 'D') " +
" AND cdow.TRM_CLASS_ID = :trmClassId " +
" ORDER BY cdow.dow";
Query sqlQuery = session.createSQLQuery(sql);
sqlQuery.setParameter("trmClassId", trmClassId);
List<Integer> classDows = sqlQuery.list();
return classDows;
}
the column dow is of type varchar(1)
I think this is the culprit on your problem.
the column dow is of type varchar(1)
Varchar should return a String result for this field. But I found that hibernate has some issue on this, when varchar contain single character, the result will be converted to char/Character datatype in your Java. Look at these issues, HHH-2220, HHH-2304 and other with the same problem. It pointed out here, and I quote
Currently Hibernate supports a kind of "automagic" mapping from SQL types to Hibernate/Java types - because of the many ambiguities in doing such mapping it will sometime not match what you actually want.
Suggestion:
Since you really expect a Character because of the above code and the issue, you should fix the datatype issue on your database and Java. You can permanently convert you database to correct datatype (Integer if it really range from 0-9). Or if you can't do database modification, you can do it by creating helper class/method to manually parse each result to Integer like using a method something like:
/**
* You parser method of Character to Integer
*/
public List<Integer> converToIngeter(List resultList){//This should accept your resultSet from your query as List
List<Integer> toReturn = new ArrayList<>();
resultList.stream().forEach((o)->{
if(Character.isDigit((Character) o)){//(Character) o) is just an insurance that the instance is Character
toReturn.add(Character.getNumericValue((Character)o));
}
});
/* Or you do some other parsing
*/
return toReturn;
}
In your code
List<Integer> getDowByTrmClassId(Integer trmClassId){
. . . //Your other code here
sqlQuery.setParameter("trmClassId", trmClassId);
List<Integer> classDows = converToIngeter(sqlQuery.list()); //converToIngeter(list) was added to convert the result to Integer
return classDows;
}
You can look other char to integer parsing like here on the internet.
Or To fix datatype problem of Varchar being returned as Character on Java, This answer suggested to add .addScalar("PREFIX", Hibernate.STRING); on your query. Eg.
sqlQuery.setParameter("trmClassId", trmClassId);
sqlQuery.addScalar("PREFIX", Hibernate.STRING);
Then, parse them to Integer later on.
===============
UPDATE:
Remove unrelated answer. Thanks you Andreas for pointing out some that I have neglected.

Hibernate-search search by list of numbers

I am working in a Hibernate-search, Java application with an entity which has a numeric field indexed:
#Field
#NumericField
private Long orgId;
I want to get the list of entities which match with a list of Long values for this property. I used the "simpleQueryString" because it allows to use "OR" logic with char | for several objective values. I have something like this:
queryBuilder.simpleQueryString().onField("orgId").matching("1|3|8").createQuery()
After run mi application I get:
The specified query '+(orgId:1 orgId:3 orgId:8)' contains a string based sub query which targets the numeric encoded field(s) 'orgId'. Check your query or try limiting the targeted entities.
So, Can some body tell me what is wrong with this code?, Is there other way to do what I need?.
=================================
UPDATE 1:
yrodiere' answer solves the issue, but I have another doubt, I want validate whether entities match other fields, I know I can use BooleanJuntion, but then I need mix "must" and "should" usages right?. i.e.:
BooleanJunction<?> bool = queryBuilder.bool();
for (Integer orgId: orgIds) {
bool.should( queryBuilder.keyword().onField("orgId").matching(orgId).createQuery() );
}
bool.must(queryBuilder.keyword().onField("name").matching("anyName").createQuery() );
Then, I am validating that the entities must match a "name" and also they match one of the given orgIds, Am I right?
As the error message says:
The specified query [...] contains a string based sub query which targets the numeric encoded field(s) 'orgId'.
simpleQueryString can only be used to target text fields. Numeric fields are not supported.
If your string was generated programmatically, and you have a list of integers, this is what you'll need to do:
List<Integer> orgIds = Arrays.asList(1, 3, 8);
BooleanJunction<?> bool = queryBuilder.bool();
for (Integer orgId: orgIds) {
bool.should( queryBuilder.keyword().onField("orgId").matching(orgId).createQuery() );
}
LuceneQuery query = bool.createQuery();
query will match documents whose orgId field contains 1, 3 OR 8.
See https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#_combining_queries
EDIT: If you need additional clauses, I'd recommend not mixing must and should in the same boolean junction, but nesting boolean junctions instead.
For example:
BooleanJunction<?> boolForOrgIds = queryBuilder.bool();
for (Integer orgId: orgIds) {
boolForOrgIds.should(queryBuilder.keyword().onField("orgId").matching(orgId).createQuery());
}
BooleanJunction<?> boolForWholeQuery = queryBuilder.bool();
boolForWholeQuery.must(boolForOrgIds.createQuery());
boolForWholeQuery.must(queryBuilder.keyword().onField("name").matching("anyName").createQuery());
// and add as many "must" as you need
LuceneQuery query = boolForWholeQuery.createQuery();
Technically you can mix 'must' and 'should', but the effect won't be what you expect: 'should' clauses will become optional and will only raise the score of documents when they match. So, not what you need here.

Retrieve String from values in HashMap at a specific occurrence of special character

So I'm trying retrieve specific substrings in values in a Hashmap constructed like this..
HashMap<ID, "Home > Recipe > Main Dish > Chicken > Chicken Breasts">
Which is passed from a different method that returns a HashMap
In above example, I need to retrieve Chicken.
Thus far, I have..
public static ArrayList<String> generalize() {
HashMap<String, String> items = new HashMap<>();
ArrayList<String> cats = new ArrayList<>();
items = RecSys.readInItemProfile("PATH", 0, 1);
for(String w : items.values()) {
cats.add(w);
}
for(String w : cats) {
int e = w.indexOf('>', 1 + w.indexOf('>', 1 + w.indexOf('>')));
String k = w.substring(e+1);
System.out.print(k);
e = 0;
}
System.out.println("k" + cats);
return cats;
}
Where I try to nullify String e for each iteration (I know it's redundant but it was just to test).
In my dataset, the first k-v pair is
3880=Home  >  Recipes  >  Main Dish  >  Pasta,
My output is
Pasta
Which is ok. If there are more than 3x ">", it'll return all following categories. Optimally it wouldn't do that, but it's ok if it does. However, further down the line, it (seemingly) randomly returns
Home > Recipe
Along with the rest of the data...
This happens at the 6th loop, I believe.
Any help is greatly appreciated..
Edit:
To clarify, I have a .csv file containing 3 columns, whereas 2 are used in this function (ID and Category). These are passed to this function by a read method in another class.
What I need to do is extract a generalized description of each category, which in all cases is the third instance of category specification (that is, always between the third and fourth ">" in every k-v pair).
My idea was to simply put all values in an arraylist, and for every value extract a string from between the third and fourth ">".
I recommend using the following map:
Map<Integer, List> map = new HashMap<>();
String[] vals = new String[] { "HomeRecipe", "Main Dish", "Chicken",
"Chicken Breasts" };
map.put(1, Arrays.asList(vals));
Then, if you need to find a given value in your original string using an ID, you can simply call ArrayList#get() at a certain position. If you don't care at all about order, then a map of integers to sets might make more sense here.
If you can. change your data structure to a HashMap<Integer, List<String>> or HashMap<Integer, String[]>. It's better to store the categories (by cats you mean categories right?) in a collection instead of a string.
Then you can easily get the third item.
If this is not possible. You need to do some debugging. Start by printing every input and output pair and find out which input caused the unexpected output. Your indexOf method seems to work at first glance.
Alternatively, try this regex method:
String k = cats.replaceAll("(?:[^>]+\\s*>\\s*){3}([^>]+).*", "$1");
System.out.println(k);
The regex basically looks for a xxx > yyy > zzz > aaa ... pattern and replaces that pattern with aaa (whatever that is in the original string).

Find String range using String parameter

I have a collection of the following type:
class Container
{
private String startValue;
private String endValue;
}
Let's say it contains these entries...
{"123, "789"},
{"1", "8"},
{"9", "10"},
Then I want to ask the collection to give me all entries which satisfy the predicate between start and end values of each Container, such as the String "5" parameter would return the two first entries above (but not the last one) whereas "9" would only return the first one (and so on).
It should behave as SQL BETWEEN operator on a VARCHAR column.
Changing type from String is not an option. Changing data structure is not an issue.
Performance is also a very importan here. The data structure is rarely changed, but retrieval is very common. A bit extra space taken if speed can be gained is also fine.
Any ideas?
Add this method to the Container class
public boolean contains(String argument) {
return argument != null && startValue.compareTo(argument) <= 0 && endValue.compareTo(argument) >= 0;
}
Then iterate through your collection, calling contains on each element.
You have to implement "Interval search tree" using red-black BST.
http://algs4.cs.princeton.edu/92search/
https://d396qusza40orc.cloudfront.net/algs4partI/slides%2F99GeometricSearch.pdf
Find all elements will cost R*logN, where R - number of elements to return, N - number of all elements.
Well... without Integer conversion and change the structure...
You can use stringToCompare.compareTo(str) to compare Strings.
Or, you can use a fixed array of Strings like {"1", "2", "3", "4", "5", "6", "7", "8", "9"}. So, you can split the Strings startValue and endValue, getting character by character and verifying the index (a int) in your array. With this int value you can do some comparisons.

Groovy / Java method for converting nested List String representation back to List

I need to convert a String representation of a nested List back to a nested List (of Strings) in Groovy / Java, e.g.
String myString = "[[one, two], [three, four]]"
List myList = isThereAnyMethodForThis(myString)
I know that there's the Groovy .split method for splitting Strings by comma for example and that I could use regular expressions to identify nested Lists between [ and ], but I just want to know if there's an existing method that can do this or if I have to write this code myself.
I guess the easiest thing would be a List constructor that takes the String representation as an argument, but I haven't found anything like this.
In Groovy, if your strings are delimited as such, you can do this:
String myString = "[['one', 'two'], ['three', 'four']]"
List myList = Eval.me(myString)
However, if they are not delimited like in your example, I think you need to start playing with the shell and a custom binding...
class StringToList extends Binding {
def getVariable( String name ) {
name
}
def toList( String list ) {
new GroovyShell( this ).evaluate( list )
}
}
String myString = "[[one, two], [three, four]]"
List myList = new StringToList().toList( myString )
Edit to explain things
The Binding in Groovy "Represents the variable bindings of a script which can be altered from outside the script object or created outside of a script and passed into it."
So here, we create a custom binding which returns the name of the variable when a variable is requested (think of it as setting the default value of any variable to the name of that variable).
We set this as being the Binding that the GroovyShell will use for evaluating variables, and then run the String representing our list through the Shell.
Each time the Shell encounters one, two, etc., it assumes it is a variable name, and goes looking for the value of that variable in the Binding. The binding simply returns the name of the variable, and that gets put into our list
Another edit... I found a shorter way
You can use Maps as Binding objects in Groovy, and you can use a withDefault closure to Maps so that when a key is missing, the result of this closure is returned as a default value for that key. An example can be found here
This means, we can cut the code down to:
String myString = "[[one, two], [three, four]]"
Map bindingMap = [:].withDefault { it }
List myList = new GroovyShell( bindingMap as Binding ).evaluate( myString )
As you can see, the Map (thanks to withDefault) returns the key that was passed to it if it is missing from the Map.
I would parse this String manually. Each time you see a '[' create a new List, each time you see a ',' add an element to the list and each time you see a ']' return.
With a recursive method.
public int parseListString(String listString, int currentOffset, List list){
while(currentOffset < listString.length()){
if(listString.startsWith("[", currentOffset)){
//If there is a [ we need a new List
List newList = new ArrayList();
currentOffset = parseListString(listString, currentOffset+1, newList);
list.add(newList);
}else if(listString.startsWith("]", currentOffset){
//If it's a ], then the list is ended
return currentOffset+1;
}else{
//Here we have a string, parse it until next ',' or ']'
int nextOffset = Math.min(listString.indexOf(',', currentOffset), listString.indexOf(']', currentOffset));
String theString = listString.substring(int currentOffset, int nextOffset);
list.add(theString);
//increment currentOffset
currentOffset = nextOffset;
}
}
return currentOffset;
}

Categories