Pagination and Sorting - custom sorting of data - spring

I have a problem with sorting data in my project.
Since I implemented pagination I don't know how solve this issue.
Before pagination I fetched whole list of entities and sort it by this class:
public class EntitySorter {
private static final Logger LOG = Logger.getLogger(EntitySorter.class);
public static int sort(String s1, String s2) {
if (StringUtils.isBlank(s1) || StringUtils.isBlank(s2)) {
return -1;
}
if (!s1.contains("/") || !s2.contains("/")) {
return -1;
}
if (s1.substring(s1.lastIndexOf("/") + 1).length() != 4 ||
s2.substring(s2.lastIndexOf("/") + 1).length() != 4) {
return -1;
}
final String year1 = s1.substring(s1.lastIndexOf("/") + 1);
final String year2 = s2.substring(s2.lastIndexOf("/") + 1);
if (!NumberUtils.isDigits(year1) || !NumberUtils.isDigits(year2)) {
return -1;
}
final int result = NumberUtils.toInt(year1) - NumberUtils.toInt(year2);
if (result != 0) {
return result;
}
final String caseNumber1 = s1.substring(0, s1.indexOf("/"));
final String caseNumber2 = s2.substring(0, s2.indexOf("/"));
if (!NumberUtils.isDigits(caseNumber1) && NumberUtils.isDigits(caseNumber2)) {
try {
final int intCaseNumber1 = Integer.parseInt(caseNumber1.replaceAll("[^0-9]", ""));
return intCaseNumber1 - Integer.parseInt(caseNumber2);
} catch (NumberFormatException e) {
LOG.error(e.getMessage(), e);
}
return -1;
}
if (NumberUtils.isDigits(caseNumber1) && !NumberUtils.isDigits(caseNumber2)) {
try {
final int intCaseNumber2 = Integer.parseInt(caseNumber2.replaceAll("[^0-9]", ""));
return Integer.parseInt(caseNumber1) - intCaseNumber2;
} catch (NumberFormatException e) {
LOG.error(e.getMessage(), e);
}
return -1;
}
if (!NumberUtils.isDigits(caseNumber1) && !NumberUtils.isDigits(caseNumber2)) {
try {
final int intCaseNumber1 = Integer.parseInt(caseNumber1.replaceAll("[^0-9]", ""));
final int intCaseNumber2 = Integer.parseInt(caseNumber2.replaceAll("[^0-9]", ""));
return intCaseNumber1 - intCaseNumber2;
} catch (NumberFormatException e) {
LOG.error(e.getMessage(), e);
}
return -1;
}
return NumberUtils.toInt(caseNumber1) - NumberUtils.toInt(caseNumber2);
}
}
Let's take some example:
We have a list of IDs:
101/2021
102/2021
1/2022
86/2020
Correct sorted list is:
1/2022
102/2021
101/2021
86/2020
In database this ID is one column. It's not split to number and year. I tried to use Sort.by() but I didn't make a success. How can I use pagination and keep correct sorting?

For pagination to work optimally, the data should be indexed correctly..
If there is a different representation of the data you can use with one column then it's the best way.
If not then the easy way would just to decompose one column to multiple columns, create a multi column index and sort by these columns + you need to understand if the natural ordering of the columns fits your logic.
The hard way would be to create user defined function and index on it and other solutions, but I would avoid the unnecessary complexity.
Keep it simple!

Related

SonarQube showing Cognitive Complexity error Even there is only 7 loops

I am review my code using SonarQube. I am receiving the following issue.
Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.
But my method contains only 7 loops. Herewith I attached the code.
private void LayoutTouch(int touchType, int index) {
if (touchType != -1) { //+1
try {
ViewConfiguration vc = ViewConfiguration.get(ctContext);
mSlop = vc.getScaledTouchSlop();
parentLayout[index]
.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v,
MotionEvent event) {
if(!isValidEvent()){ //+2
return false;
}
if(checkTouchIndex(index)){ //+3
try{
// Code here
if (animationStarted) { //+4
return false;
}
final ViewConfiguration vc = ViewConfiguration
.get(getContext());
final int deltaX = (int) (event.getX() + 0.5f)
- mGestureCurrentX;
initiateVelocityTracker();
mVelocityTracker.addMovement(event);
mVelocityTracker
.computeCurrentVelocity(1000);
if(!doSwitchAndNeedToReturn(v, event, index, vc, deltaX)) // +5
return false;
}catch(Exception e){ //+6
setTouchProgressIndex(-1);
}finally{
setTouchProgressIndex(-1);
}
}
return false;
}
});
} catch (Exception e) { //+7
Log.e("Testing","Exception "+ e);
}
}
}
Why I am getting this issue. Please help me on this.
I agree with SonarQube that the code is overly complex.
Simplifications possible:
combine if statements
use a lambda
(not done here) use an extra method for the lambda code
So:
private void LayoutTouch(int touchType, int index) {
if (touchType != -1) { //+1
try {
ViewConfiguration vc = ViewConfiguration.get(ctContext);
mSlop = vc.getScaledTouchSlop();
parentLayout[index]
.setOnTouchListener((v, event) -> {
if (isValidEvent() && checkTouchIndex(index)) {
try{
// Code here
if (animationStarted) { //+4
return false;
}
final ViewConfiguration vc = ViewConfiguration
.get(getContext());
final int deltaX = (int) (event.getX() + 0.5f)
- mGestureCurrentX;
initiateVelocityTracker();
mVelocityTracker.addMovement(event);
mVelocityTracker
.computeCurrentVelocity(1000);
if (!doSwitchAndNeedToReturn(v, event, index, vc, deltaX)) // +5
return false;
} catch(Exception e) { //+6
setTouchProgressIndex(-1);
} finally {
setTouchProgressIndex(-1);
}
}
return false;
});
} catch (Exception e) { //+7
Log.e("Testing","Exception "+ e);
}
}
}
The extra method:
.setOnTouchListener(this::onTouch);
private boolean onTouch(View v, MotionEvent event) {
...
}
The checked exception handling is very unspecific. If not a specific exception can happen, maybe drop it (at the end).
Using member variables named with the prefix m, is not conventional in java. These variables indeed seem many, but with mouse, touch and so that might make sense.
I mention this, as the calculations seem refactorable.
But my method contains only 7 loops
Sonar is telling you that the method is hard to understand (cognitive complexity). And I do agree with the criteria. The complexity does not grow linearly and that is why it goes +1, +2, +3, +4 +5 +6 +7 = 28 > 21.
As a developer I would really want this piece of code cleaned up. Here are some suggestions:
Extract the OnTouchListener into a class (inner or not)
Change the initial check as a guard condition with an early return.
Review why are you doing the same thing in finally and the exception. setTouchProgressIndex(-1)

How to retrieve filtered value from a stream and use it

I'm new to Java 8:
I have to convert this piece of java 6 code to java 8 version:
List<String> unvalidnumbers = new ArrayList<>();
StringBuilder content = new StringBuilder();
String str = "current_user"
for (Iterator<String> it = numbers.iterator(); it.hasNext();) {
String number = it.next();
try {
PersIdentifier persIdentifier = this.getPersIdentifierByNumber(number);
if (persIdentifier != null) {
content.append(number).append(";").append(str);
if (StringUtils.equals(persIdentifier.getType(), "R")) {
content.append(";X");
}
if (it.hasNext()) {
content.append("\r\n");
}
}
} catch (BusException e) {
LOGGER.warn("Pers not found", e);
unvalidnumbers.add(number);
}
}
So i wrote this:
numbers.stream().filter((String number) -> {
try {
return this.getPersIdentifierByNumber(number) != null;
} catch (BusinessException e1) {
LOGGER.warn("Pers not found", e1);
return false;
}
}).forEach(number -> contentConstruction.append(number).append(";").append(str));
I know it's missing this part:
if (StringUtils.equals(persIdentifier.getType(), "R")) {
content.append(";X");
}
if (it.hasNext()) {
content.append("\r\n");
}
But i didn't found way to retrieve the corresponding persIdentifier object.
Any idea please
You should use a more functional approach if you use Java 8.
Instead of a forEach, favor collect(). Here Collectors.joining() looks suitable.
Not tested but you should have an overall idea :
String result =
numbers.stream()
.map(number -> new SimpleEntry<String, PersIdentifier>(number, this.getPersIdentifierByNumber(number) )
.filter(entry -> entry.getValue() != null)
.map(entry ->{
final String base = entry.getKey() + ";" + str;
return "R".equals(entry.getValue().getType()) ? base + ";X" : base;
})
.collect(joining("\r\n")); // Or not OS dependent : System.lineSeparator()

Converting a linq query or foreach loop into a form that is awaitable

I am trying to convert my method to Async. I cannot seem to grasp converting a linq query or foreach loop into a form that is awaitable. I read here on SO that EntityFramework + Linq don’t mix very well asynchronously. Perhaps that is why I could not find a previous Question that matches my needs exactly. Would someone care to point me in the right direction?
private static async Task<decimal> GetLastPriceAsync(string customer, string stockNumber)
{
Debug.WriteLine("Get Last Price Called");
decimal lastCost = 0;
var lastDate = new DateTime(1900, 1, 1);
if (string.IsNullOrEmpty(customer))
{
Debug.WriteLine("There was no customer");
return 0;
}
Debug.WriteLine("We have a customer");
if (string.IsNullOrEmpty(stockNumber))
{
Debug.WriteLine("There was no item");
return 0;
}
Debug.WriteLine("We have a Part Number");
try
{
IEnumerable<SA_HistoryHeader> orders =
DContext.SA_HistoryHeader.Local.Where(c => c.strCustomer == customer);
if (!orders.Any())
{
Debug.WriteLine("No order found.");
return 0;
}
Debug.WriteLine("We have previous Orders Found");
foreach (SA_HistoryHeader thisOrder in orders)
{
Debug.WriteLine("Looping through orders.");
DateTime date = lastDate;
IEnumerable<SA_HistoryDetail> details = thisOrder.SA_HistoryDetail
.Where(i => i.strStock == stockNumber && i.dteLineDate > date && i.bytLineType == 003);
foreach (
SA_HistoryDetail detail in
details.Where(detail => detail != null && !string.IsNullOrEmpty(detail.strDescription)))
{
if (detail.dteLineDate != null)
{
lastDate = (DateTime) detail.dteLineDate;
}
else
{
Debug.WriteLine("Order Date was null");
}
if (detail.curUnitPrice != null)
{
lastCost = (decimal) detail.curUnitPrice;
}
else
{
Debug.WriteLine("Last Cost was null");
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine("Last Price Calc Error: " + ex.InnerException.Message);
}
return lastCost;
}

Gwt CellTable Sorting page by page only

GWT CellTable column sorting page by page only, for each page i have to click the column header
for sorting.
How to sort whole data on single header click.
This is my code,
dataProvider = new ListDataProvider<List<NamePair>>();
dataProvider.addDataDisplay(dgrid);
List<List<NamePair>> list = dataProvider.getList();
for (List<NamePair> contact : test) {
dataProvider.setList(test);
list.add(contact);
}
ListHandler<List<NamePair>> columnSortHandler = new ListHandler<List<NamePair>>(dataProvider.getList());
System.out.println("Column count->"+dgrid.getColumnCount());
for(int j=0 ; j<dgrid.getColumnCount();j++){
final int val = j;
columnSortHandler.setComparator(dgrid.getColumn(val), new Comparator<List<NamePair>>() {
public int compare(List<NamePair> o1, List<NamePair> o2) {
if (o1 == o2) {
return 0;
}
// Compare the column.
if (o1 != null) {
int index = val;
return (o2 != null) ? o1.get(index-2).compareTo(o2.get(index-2)) : 1;
}
return -1;
}
});
}
dgrid.addColumnSortHandler(columnSortHandler);
I suggest you override ListHandler , override and call super.onColumnSort(ColumnSortEvent) to debug the onColumnSort(ColumnSortEvent) method, you'll understand what is happening very fast.
The source code of the method is pretty direct
public void onColumnSort(ColumnSortEvent event) {
// Get the sorted column.
Column<?, ?> column = event.getColumn();
if (column == null) {
return;
}
// Get the comparator.
final Comparator<T> comparator = comparators.get(column);
if (comparator == null) {
return;
}
// Sort using the comparator.
if (event.isSortAscending()) {
Collections.sort(list, comparator);
} else {
Collections.sort(list, new Comparator<T>() {
public int compare(T o1, T o2) {
return -comparator.compare(o1, o2);
}
});
}
}

Lossless hierarchical run length encoding

I want to summarize rather than compress in a similar manner to run length encoding but in a nested sense.
For instance, I want : ABCBCABCBCDEEF to become: (2A(2BC))D(2E)F
I am not concerned that an option is picked between two identical possible nestings E.g.
ABBABBABBABA could be (3ABB)ABA or A(3BBA)BA which are of the same compressed length, despite having different structures.
However I do want the choice to be MOST greedy. For instance:
ABCDABCDCDCDCD would pick (2ABCD)(3CD) - of length six in original symbols which is less than ABCDAB(4CD) which is length 8 in original symbols.
In terms of background I have some repeating patterns that I want to summarize. So that the data is more digestible. I don't want to disrupt the logical order of the data as it is important. but I do want to summarize it , by saying, symbol A times 3 occurrences, followed by symbols XYZ for 20 occurrences etc. and this can be displayed in a nested sense visually.
Welcome ideas.
I'm pretty sure this isn't the best approach, and depending on the length of the patterns, might have a running time and memory usage that won't work, but here's some code.
You can paste the following code into LINQPad and run it, and it should produce the following output:
ABCBCABCBCDEEF = (2A(2BC))D(2E)F
ABBABBABBABA = (3A(2B))ABA
ABCDABCDCDCDCD = (2ABCD)(3CD)
As you can see, the middle example encoded ABB as A(2B) instead of ABB, you would have to make that judgment yourself, if single-symbol sequences like that should be encoded as a repeated symbol or not, or if a specific threshold (like 3 or more) should be used.
Basically, the code runs like this:
For each position in the sequence, try to find the longest match (actually, it doesn't, it takes the first 2+ match it finds, I left the rest as an exercise for you since I have to leave my computer for a few hours now)
It then tries to encode that sequence, the one that repeats, recursively, and spits out a X*seq type of object
If it can't find a repeating sequence, it spits out the single symbol at that location
It then skips what it encoded, and continues from #1
Anyway, here's the code:
void Main()
{
string[] examples = new[]
{
"ABCBCABCBCDEEF",
"ABBABBABBABA",
"ABCDABCDCDCDCD",
};
foreach (string example in examples)
{
StringBuilder sb = new StringBuilder();
foreach (var r in Encode(example))
sb.Append(r.ToString());
Debug.WriteLine(example + " = " + sb.ToString());
}
}
public static IEnumerable<Repeat<T>> Encode<T>(IEnumerable<T> values)
{
return Encode<T>(values, EqualityComparer<T>.Default);
}
public static IEnumerable<Repeat<T>> Encode<T>(IEnumerable<T> values, IEqualityComparer<T> comparer)
{
List<T> sequence = new List<T>(values);
int index = 0;
while (index < sequence.Count)
{
var bestSequence = FindBestSequence<T>(sequence, index, comparer);
if (bestSequence == null || bestSequence.Length < 1)
throw new InvalidOperationException("Unable to find sequence at position " + index);
yield return bestSequence;
index += bestSequence.Length;
}
}
private static Repeat<T> FindBestSequence<T>(IList<T> sequence, int startIndex, IEqualityComparer<T> comparer)
{
int sequenceLength = 1;
while (startIndex + sequenceLength * 2 <= sequence.Count)
{
if (comparer.Equals(sequence[startIndex], sequence[startIndex + sequenceLength]))
{
bool atLeast2Repeats = true;
for (int index = 0; index < sequenceLength; index++)
{
if (!comparer.Equals(sequence[startIndex + index], sequence[startIndex + sequenceLength + index]))
{
atLeast2Repeats = false;
break;
}
}
if (atLeast2Repeats)
{
int count = 2;
while (startIndex + sequenceLength * (count + 1) <= sequence.Count)
{
bool anotherRepeat = true;
for (int index = 0; index < sequenceLength; index++)
{
if (!comparer.Equals(sequence[startIndex + index], sequence[startIndex + sequenceLength * count + index]))
{
anotherRepeat = false;
break;
}
}
if (anotherRepeat)
count++;
else
break;
}
List<T> oneSequence = Enumerable.Range(0, sequenceLength).Select(i => sequence[startIndex + i]).ToList();
var repeatedSequence = Encode<T>(oneSequence, comparer).ToArray();
return new SequenceRepeat<T>(count, repeatedSequence);
}
}
sequenceLength++;
}
// fall back, we could not find anything that repeated at all
return new SingleSymbol<T>(sequence[startIndex]);
}
public abstract class Repeat<T>
{
public int Count { get; private set; }
protected Repeat(int count)
{
Count = count;
}
public abstract int Length
{
get;
}
}
public class SingleSymbol<T> : Repeat<T>
{
public T Value { get; private set; }
public SingleSymbol(T value)
: base(1)
{
Value = value;
}
public override string ToString()
{
return string.Format("{0}", Value);
}
public override int Length
{
get
{
return Count;
}
}
}
public class SequenceRepeat<T> : Repeat<T>
{
public Repeat<T>[] Values { get; private set; }
public SequenceRepeat(int count, Repeat<T>[] values)
: base(count)
{
Values = values;
}
public override string ToString()
{
return string.Format("({0}{1})", Count, string.Join("", Values.Select(v => v.ToString())));
}
public override int Length
{
get
{
int oneLength = 0;
foreach (var value in Values)
oneLength += value.Length;
return Count * oneLength;
}
}
}
public class GroupRepeat<T> : Repeat<T>
{
public Repeat<T> Group { get; private set; }
public GroupRepeat(int count, Repeat<T> group)
: base(count)
{
Group = group;
}
public override string ToString()
{
return string.Format("({0}{1})", Count, Group);
}
public override int Length
{
get
{
return Count * Group.Length;
}
}
}
Looking at the problem theoretically, it seems similar to the problem of finding the smallest context free grammar which generates (only) the string, except in this case the non-terminals can only be used in direct sequence after each other, so e.g.
ABCBCABCBCDEEF
s->ttDuuF
t->Avv
v->BC
u->E
ABABCDABABCD
s->ABtt
t->ABCD
Of course, this depends on how you define "smallest", but if you count terminals on the right side of rules, it should be the same as the "length in original symbols" after doing the nested run-length encoding.
The problem of the smallest grammar is known to be hard, and is a well-studied problem. I don't know how much the "direct sequence" part adds to or subtracts from the complexity.

Resources