简体   繁体   中英

How to show all the values that start with a specific number

I'm creating a search to filter some Integer values from 100 to 600. These values are Http Status Codes , so I want just to filter them.
The way the search should work is as follows:

  1. User enters a search value eg 2 and clicks search
  2. The result will be, all the values from 200 to 299 (so all the values starting with 2).
  3. User enters a value eg 20 and clicks search
  4. The result will be, all the values from 200 to 209 (so all the values starting with 20).
  5. User enters a value eg 52 and clicks search
  6. The result will be, all the values from 520 to 529 (so all the values starting with 52)

I wrote some code which is very redundant, but basically explains how it should work:

     public void getHttpStatus(Integer httpStatus){
            if(httpStatus.equals(1)){
                messageRepository.findByHttpStatusBetween(100, 199);
            }
            else if(httpStatus.equals(2)){
                messageRepository.findByHttpStatusBetween(200, 299);
            }
            else if(httpStatus.equals(3)){
                messageRepository.findByHttpStatusBetween(300, 399);
            }
            else if(httpStatus.equals(4)){
                messageRepository.findByHttpStatusBetween(400, 499);
            }
            else if(httpStatus.equals(5)){
                messageRepository.findByHttpStatusBetween(500, 599);
            }
            else if(httpStatus.equals(10)){
                messageRepository.findByHttpStatusBetween(100, 109);
            }
            else if(httpStatus.equals(20)){
                messageRepository.findByHttpStatusBetween(200, 209);
            }
            else if(httpStatus.equals(30)){
                messageRepository.findByHttpStatusBetween(300, 309);
            }
            else if(httpStatus.equals(40)){
                messageRepository.findByHttpStatusBetween(400, 409);
            }
            else if(httpStatus.equals(50)){
                messageRepository.findByHttpStatusBetween(500, 509);
            }
            else if(httpStatus.equals(21)){
                messageRepository.findByHttpStatusBetween(210, 219);
            }
            ...
        }

Is there any simpler way to do this? or is there any build-in spring method that does this automatically?

I would appreciate any suggestion.

Assuming that you have a list containing all status codes you could use a stream filter ie

List<Integer> httpCodes;
String prefix = "5"
List<Integer> filteredResults = httpCodes.stream().filter(value -> value.toString().startsWith(prefix)).collect(Collectors.toList());

Store the code as a string, write a custom query that looks for entries that are "LIKE '50%'" etc. (LIKE '$1%').

Here are also other alternatives to solve this slightly different: SQL LIKE condition to check for integer?

I would probably do it like this:

public void getHttpStatus(Integer httpStatus){
 int numberOfDigits = (int) (Math.log10(number) + 1);
 int minStatus = httpStatus * ((int) Math.pow(10, 3 - numberOfDigits));
 int maxStatus = (httpStatus + 1) * ((int) Math.pow(10, 3 - numberOfDigits)) - 1
 messageRepository.findByHttpStatusBetween(minStatus,maxStatus)

}

or You can do it like this,

String status=  httpStatus.toString();
String startIndex = status;
String endIndex = status;

if ( status.length() == 1 )
{
    startIndex = status + "00";
    endIndex = status + "99";
}
else if ( status.length() == 2 )
{
    startIndex = status + "0";
    endIndex = status + "9";
}
int sIndex = Integer.parseInt( startIndex );
int eIndex = Integer.parseInt( endIndex );

messageRepository.findByHttpStatusBetween(sIndex, eIndex);

If the values are integers (or just compatible with the operation in general, you could always use modulo ( % ) to filter. ie like this:

void getStatus(httpCode){
    for(int i : codeList){
        if(i%httpCode >= 1) print i;
     }
}

Apologies for the pseudo-code, hope it helps anyways.

Edit: I realize there's a need for an upper bound, So this is probably not ideal. You could still implement it this way, just beware that that may be a major pain.

public class Range {
    public int lb;
    public int ub;

    public Range(int lb, int ub) {
        this.lb = lb;
        this.ub = ub;
    }

    public Range(int statusCode) {
        int length = (int) (Math.log10(statusCode) + 1);
        if (length == 0 || length > 2) {
            throw new RuntimeException("Cant parse status code of invald length: " + length);
        }
        if (length == 1) {
            this.lb = statusCode * 100;
            this.ub = ((statusCode + 1) * 100) - 1;
        } else {
            this.lb = statusCode * 10;
            this.ub = ((statusCode + 1) * 10) - 1;
        }
    }
}


public class Main {
    public static void main(String[] args) {
        Range r1 = new Range(52);
        Range r2 = new Range(2);
        Range r3 = new Range(20);
        System.out.println("Lowerbound: " + r1.lb);
        System.out.println("Upperbound: " + r1.ub);
        System.out.println("Lowerbound: " + r2.lb);
        System.out.println("Upperbound: " + r2.ub);
        System.out.println("Lowerbound: " + r3.lb);
        System.out.println("Upperbound: " + r3.ub);
    }
}

Output is as following:

Lowerbound: 520
Upperbound: 529
Lowerbound: 200
Upperbound: 299
Lowerbound: 200
Upperbound: 209

Does not check for special value 0.

Then your function can be refactored to:

public void getHttpStatus(Integer httpStatus){
        Range r = new Range(httpStatus.intValue());
        messageRepository.findByHttpStatusBetween(r.lb, r.ub);
}

One solution to your problem is build a trie and search in it using the digits in the user input as keys:

https://en.wikipedia.org/wiki/Trie

Another solution is to build a hash table and insert all possible prefixes along with their ranges. (For instance, since the user input 21 is the prefix of codes 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, we add (21, 210, 219) to the table, where 21 is the key, 210 the lower bound, and 219 the upper bound. Likewise for all other possible user inputs.)

There are at most 500 three-digit codes, which means the table will have 1500 entries at most.

Since all keys and ranges are known in advance and constant, you can even use perfect hashing and be able to find the ranges in constant time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM