iSortBox


Source link: https://github.com/sucong0826/iSortBox

iSortBox

Summary

What is iSortBox? Just like what it says: Simplify sorting!

This framework achieves a goal which makes sorting easier, moreover, you will benefit from what it provides such as pre-processing, converting, grouping and filtering.

As the name iSortBox, the letter 'i' means input and the letter 'o' means output, as for the details on how to complete the work, all are encapsulated in iSortBox.

Design Prototype

In this chapter, some pictures about iSortBox will be posted here.

Why iSortBox?

What iSortBox tries to solve is to standardize the usage of sorting in a project. That's the aim of iSortBox. There are no advanced skills and technologies in iSortBox, instead, it just simplifies sort by encapsulating several standardized and processed steps to make you sort easily.

Therefore, iSortBox acts as a helper framework. Once you want to sort a disordered set, iSortBox will help you solve the sort issue.

iSortBox Prototype

There are two necessary parts and two optional parts in the design prototype.

The necessary parts are

  • Process (part 1)
  • Sort (part 2)

The optional parts are

  • Group (part 3)
  • Filter (part 4)

These parts are obtained through a lot of trying and analyzing. In order to complete sort, these parts are enough for developers.

Next, I will analyze each part with code and how to make full use of these parts.

Analysis

Before the analysis, I introduce a class named Student. It is used to code samples.

public class Student {

  private int id;
  private String name;
  private int age;
  private float weight;

 public Student(int id, String name, int age, float weight) {

this.id = id;

this.name = name;

this.age = age;

this.weight = weight;
  
}

 public int getId() {

return this.id;
  
}

 public String getName() {

return this.name;
  
}

 public int getAge() {

return this.age;
  
}

 public float getWeight() {

return this.weight;
  
}
 
}

Part-1/2 Process and Sort

The part of process is going to complete several steps, it contains :

  1. Receive an input
  2. Pre-process (optional)
  3. Configure sort
  4. Find sort keys
  5. Convert
  6. Sort
  7. Sample

1.1 Receive an input

As the prototype mentioned, iSortBox needs an input entrance. Presume that there is a list of Student.

List<Student> studentList = new ArrayList<>(4);
 studentList.add(new Student(3, "Daniel", 14, 89.3f));
 studentList.add(new Student(1, "Larry", 13, 65.5f));
 studentList.add(new Student(20, "John", 14, 74.0f));
 studentList.add(new Student(15, "Lyn", 10, 70.2f));

Now, four students are generated. The list studentList is going to be ordered by iSortBox, Now, the list acts as input to enter the iSortBox, that is, the receiving an input.


1.2 Pre-process (Optional)

Then you may want to pre-process your input. Step 2 Pre-process will do it. In iSortBox, an interface named Process existing the package underneath sortbox.common.process undertakes the task. You can define a new interface to extend it or a new class to implement it. For example :

public class InputListProcess implmenents Process<List<?>> {

  @Override
  public void process(List<?> target, Object... args) {

removeEmpty(target);

  
}
 
}

You can create the instance of it to be used as an argument passed into a method in SortExecutor. Anyway, this step is optional.

Use pre-process before sorting when you need.


1.3 Configure Sorting

In iSortBox, sort is regarded as sort a collection by one property or some properties.

For example, you may need the studentList to be sorted by id from 1 to N. You may need to sort the list by name from 'a' to 'z'. The actual intent of sort is to sort values on some properties.

Sort is a process to define a Comparator. If you think that sort is as simple as defining a Comparator, why to write the iSortBox instead of using Comparator directly? If you know only one known property and use this property to sort a list, nothing different. In contrast, using Comparator directly will save lots of resources.

Collections.sort(studentList, new Comparator<>() {

  @Override
  public int compare(Student s1, Student s2) {

return s1.getId() - s2.getId();

  
}
 
}
);

However, there is a more common case, you don't know which property will be used to sort a list at all until clients or users trigger a sort by a certain property they select. Just like Excel.

Users may select the column of id to sort the studentList or select the column of name to sort.

For the cases above, developers can still use Comparator to complete the task. But iSortBox provides a more convenient way to do it.

The mechanism is reflection in Java.

First of all, iSortBox uses reflection to generate a PropertyTable which holds the properties information of T, the Student. The PropertyTable records the name of a property, the type of a property, and the value of a property. The object is used to be searched by developers and provided to show at some UI interface for being selected by users.

List<PropertyTableItem> list = new PropertyTable<Student>().check(studentList.get(0)).getPropertyList();

Or

List<PropertyTableItem> list = new PropertyTable<Student>().check(Student.class).getPropertyList();

If you only want to get the name and type of properties without concrete values, the latter is better.

Well, iSortBox gives us a table recording properties information, for developers and users, are able to specify some properties to sort a list. It's time to introduce the SortConfig<T> class. SortConfig<T> is a manifest file.

SortConfig<Student> config = new SortConfig<Student>().new Builder()
  .set(1, "id", new NumberOrderComparator<>(true))
  .set(2, "name", new NameComparator<>())
  .combineMode(CombineMode.MULTIPLE)
  .useDefaultComparator(false)
  .build();

Please look at the code, T is the generic type of Student which means that the configuration is provided by an instance of Student. It's easy to use Builder Pattern to build up a configuration. Now set(int priority, String propertyName, AbstractComparator<T> comparator)method is the key of the whole configuration.

  • int priority : means that the property is given to a priority when sort happens. The level in a range from 0 to N indicates the highest level to lowest level.

  • String propertyName : means that the name of a property.

  • AbstractComparator<T> comparator: means that how to sort a list, it can be null.

    Well, a call to set(1, "id", new NumberOrderComparator<>(true)) means that a list will be sorted by id using NumberOrderComparator firstly.

combineMode(CombineMode.MULTIPLE) is easy to understand. CombineMode is an enumeration class which has two instances of SINGLE and MULTIPLE.

  • SINGLE: means that users and developers can only specify one property which has the highest priority to sort a list , the others will be dropped off. However if you specify more than one properties, only one property will be kept, the one which has the highest priority. If you specify one property only but the property doesn't exist, a failed sorting but iSortBox will return you the original data list that encapsulated in SortResult.

  • MULTIPLE: means that you can specify more than one properties, no amount limitation. Those you specify will be saved in a map, its key is TwoTuple<Integer, String>, its value is AbstractComparator<T>. The map is a middle variable, later, those will be handled. Here, you just need to know that MULTIPLE allows you to specify more properties.

useDefaultComparator(boolean use) is an error compatible method. When you call set(..) and pass in a null Comparator, you can setup this method to notify iSortBox whether to enable the default comparator DefaultComparator. If you set false meanwhile comparator is null, iSortBox will return you the original data list that encapsulated in SortResult.

When build() is called, an instance of SortConfig<T> will be generated.


1.4 Find sort keys (private implementation)

Once you specify the properties whatever you give or you select from PropertyTable, Find sort keys is an important step. iSortBox is going to pick out these properties you select then it checks whether these properties are truly existing through PropertyTable or direct reflection. After checking, the remaining properties will be put into SortKey which has the same role as PropertyTableItem.

The result of finding sort keys is List<TwoTuple<T, Queue<SortKey>>>. TwoTuple<F, S> is a kind of skill that makes two objects become one object. As above, T can be regarded as the type of Student, Queue<SortKey> is a set of SortKey which holds the information of specified properties.


1.5. Convert (private implementation)

Before illustrating what is convert, let's familiar with a class SortItem<T>. This class collects a set of SortKeyand keeps an original data of T. Actually, when SortExecutor executes a sort, it sorts a list of SortItem<T>. You are maybe puzzled about this, but class SortItem<T> is a middle component as well, it belongs to the inner detail of iSortBox framework. The reason of why this class is designated in iSortBox is to complete a sort but keeps the original data.


1.6 Sort

Step Sort is the simplest one in these steps.

What is sorting for Java? If you find out the answer, the principle of iSortBox is so easy to understand.

In Java, sort is the Comparator !

No matter how complicated the sorting rules are, just to define your own Comparators. As I mentioned above, iSortBox is not the expert at algorithm and effectiveness of sort, to be honest, those more efficient algorithms are beyond my abilities.

So, defining your comparators under different cases or demands is the key step. Sorter<T> class takes charge in sorting a list. Actually, a SortConfig<T> is attached with some AbstractComparators, as for the further call, iSortBox just call Collections.sort(..) to sort a list.


1.7 Sample

SortConfig<Student> sortConfig = new SortConfig<Student>().new Builder()

 .set(4, "id", new NumberOrderComparator<>(true))

 .set(1, "name", new NameComparator<>())

 .combine(CombineMode.SINGLE)

 .useDefaultComparator(false)

 .build();
  SortedResult<Student> result = new SortExecutor<Student>()

 .input(studentList)

 .preProcess(null)

 .sortConfig(sortConfig)

 .sort();

// must && call in order

Part-3 Group (Optional)

Grouping is a useful and optional part. What's the aim? If you have a demand like this: Please group students into different groups by their age. There are three defined groups by age, 0 - 10 / 10 - 20 / 20 - n. And you should group the student list by this rule before sorting or after sorting. Grouping will cause two kinds of result:

  1. Before sorting : If grouping is previous to sorting, iSortBox will generate a list of Group<T>, each Group<T> holds a list of T that satisfies the group condition. You'd better not to worry about this, even grouping is previous to sorting, you can sort the list of T from Gruop<T>, the result is same.

  2. After sorting : Normal case.

What is the concept of Grouping? Grouping is an action that gathers a collection of the object satisfying a condition. For example, 10 < age < 20 is a condition, if a student's age is 15, it will be grouped into a group collecting the age from 10 to 20.

However, how to express the abstract concept in a Programming Language? Grouping is an abstract concept absolutely because you can't give an exact description at all. The reason why we can't describe it is that we regard it as OOP (Object-Oriented-Programming), not Functional Programming.

That's right! Group part is applied to functional programming. If we try to understand that a group is equaled to a condition, the condition is a function. Therefore, iSortBox uses java.util.function.Predicate to achieve the goal. In design pattern, it is the Strategy Pattern. The strategy is an interface. For Predicate<T>, it is a functional interface that provides a function boolean test(T var1), if a var1 passes the test(..), that is, returns true, predicate successfully. You can compose your own strategies as demand required.

As for iSortBox, GroupCondition implements it.

public abstract class GroupCondition<T> implements Predicate<T> {

  private List<T> input;
  private Group<T> mGroup;

 public GroupCondition(List<T> input, Object key) {

...
  
}

  public abtract Group<T> execute();
 
}

For example. If we want to collect some students whose age is in range of 15 - 20 years old, we can do like this :

public class AgeGroupCondition<Student> extends GroupCondtion<Student> {

  private List<Student> studentList;
  private int from;
  private int to;

 public AgeGroupCondition(List<Student> input, String key, int from, int to) {

super(input, key);

this.studentList = input;

this.from = from;

this.to = to;
  
}

 @Override
  public Group<Student> execute() {

studentList.stream().filter(this).forEach(this::shot);

 return getGroup();

  
}

 @Override
  public boolean test(Student student) {

int age = student.getAge();

return age >= from && age < to;
  
}
 
}

How to use this AgeGroupCondtion, GroupExecutor will help.

  1. Create an instance of GroupExecutor and execute the condition.
  2. Get the data you need.
GroupExecutor executor = GroupExecutor.newInstance();
 Group<Student> group = executor.executeSingle(new AgeGroupCondtion(input, "age", 15, 20));
 List<Student> groupedStudents = group.getDataList();
 System.out.println(Arrays.toString(groupedStudents.toArray()));

Part-4 Filter (Optional)

Why iSortBox supports filter? The mechanism of Filter is same as Group. Both are applied to functional programming with java.util.function.Predicate. However, their intents are different. Filter tends to remove something.

The Filter is an optional part, that is, you can filter anywhere as you need.

Filter in iSortBox

public interface Filter<T> extends Predicate<T> {

  void filter(T t);
 
}

You can define your own filters as demand required. For example, if we want to remove the first element in a list, do like this:

public class RemoveFirstFilter<T> extends ListFilter<T> {

 @Override
  public void filter(List<T> input) {

super.filter(input);

input.remove(0);

  
}

 @Override
  public void test(List<T> input) {

// useless here.

return false;
  
}
 
}

Note that, ListFilter is a pre-defined filter in class which is used to filter a list.

How to execute the filter?

FilterExecutor executor = FilterExecutor.newInstance();
 executor.execute(group.getDataList(), new RemoveFirstFilter<>());

Data Flow

Declaration

1. About iSortBox

First of all, iSortBox is still in beta version. I finished it in plan and wrote codes by design. All the projects I start right now are aimed at practicing and learning. There are so many things to learn and conclude, write code and it'd better be applied to some actual issues.

Thus, I think iSortBox is not the best solution to solve sorting issue but the best way for me to digest what I've learned.

If you want to take it to you official projects or important projects, please CONSIDER CAREFULLY.

2. Shortcomings

As a newborn project, iSortBox has some shortcomings and something worth improving.

  1. SortKey and PropertyTableItem are both kept in the project. Actually, they should be merged into one to express the same meaning.

  2. I still think the cases that iSortBox can be applied to are limited and meaningless. However, this shortcoming should be dug further.

  3. If iSortBox is measured by a good framework, it is a bit of complicated. The kind of complexity is not the usage, is implementation. In terms of learning, it is accepted.

  4. If the number of the disordered objects is huge, in other words, the efficiency is not tested under the case.

  5. Specifying a property by name is unreliable.

  6. Java 8 or later versions is required.

3. Improvement

Annotation is a better solution, I deem.

Resources

CircularProgressbar project lets you to create a circular progressbar in the simplest way.

This library uses the power of RxJava to wrap an Observable android Activity#onActivityResult() method so you can easily request something from other activities and have the result right there in your observabale's subscribe() method.

Main Benefits

  • Don't Break The Chain: Prevents you to split your code between the permission request and the result handling. Currently without this library you have to request in one place and handle the result in Activity#onActivityResult().
  • Reactive: All what RX provides about transformation, filter, chaining...

Circle Time View is an android custom view for displaying time in a pretty format. The View is highly customizable, so you can adapt the appearance according your needs.

You can use this view to create countdown timers, alarms or just allow user to set time manually.

This library requires API level 8 or higher.

A fancy CircularProgressView.

Sometimes when working with REST APIs in Android apps there is a need to return some mock data. Maybe for demo purposes, or real endpoint is just not ready yet. Endpoint2mock aims to help with that by integrating with Retrofit and allowing you to easily redirect some (but not all!) of your requests to your mock server.

A light weight library for exporting and importing sqlite database in android.

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes