给json数组中的元素排序

给json数组中的元素排序

起因

基本信息

  • 平台:windows

  • IDE:Lazarus 2.2.6

  • json包:FPC自带的fpjson

背景

最近在搞一个小工具,数据文件采用的是json格式,其中一个节点存放的是一组文件的基本信息的清单,这个节点自然就是个json数组,元素就是每个文件基本信息的json对象。界面展示用的是经典的DBGrid + DataSource + DataSet方案,所以会把json数组转为DataSet

操作过程中会比对磁盘上的文件,该添的添,该删的的删,该改的改,该标记的标记。一番操作下来,顺序自然是乱的,虽然可以操作DataSet或者换用带排序功能的DBGridEh达到排序的目的,但直接看json数据的话,依然是乱序的。因此,期望直接对json数组进行排序。

解决过程

习惯先看源码,如果没有原生解决方案了,或者原生解决方案太别扭了,才会选择第三方解决方案或自己造轮子。

一看源码

pascal 复制代码
TJSONArray = class(TJSONData)
public
  ...
  Procedure Sort(Compare: TListSortCompare);

TJSONArray已经提供了排序方法,不过这个参数是什么东西?

pascal 复制代码
TListSortCompare = function (Item1, Item2: Pointer): Integer;

嗯,是个函数声明,也就是说具体的算法实现要自己写,可以先找找看有默认的实现没。结果是:没有!那就自己写吧。

看声明,这个函数是要比较两个指针指向的东西,并返回一个整数。嗯,看上去很简单,不过:

  • 到底是怎么实现排序的?

  • 参数是指针,指向的又是什么东西?

  • 返回一个什么样的整数才能实现排序呢?

没懂!!!

还是接着看源码吧:

pascal 复制代码
procedure TJSONArray.Sort(Compare: TListSortCompare);
begin
  FList.Sort(Compare);
end; 

Procedure TFPObjectList.Sort(Compare: TListSortCompare);
begin
  FList.Sort(Compare);
end; 

procedure TFPList.Sort(Compare: TListSortCompare);
begin
  if Not Assigned(FList) or (FCount < 2) then exit;
  QuickSort(Flist, 0, FCount-1, Compare);
end;  

Procedure QuickSort(FList: PPointerList; L, R : Longint;
                     Compare: TListSortCompare);
var
  I, J : Longint;
  P, Q : Pointer;
begin
 repeat
   I := L;
   J := R;
   P := FList^[ (L + R) div 2 ];
   repeat
     while Compare(P, FList^[i]) > 0 do
       I := I + 1;
     while Compare(P, FList^[J]) < 0 do
       J := J - 1;
     If I <= J then
     begin
       Q := FList^[I];
       Flist^[I] := FList^[J];
       FList^[J] := Q;
       I := I + 1;
       J := J - 1;
     end;
   until I > J;
   // sort the smaller range recursively
   // sort the bigger range via the loop
   // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
   if J - L < R - I then
   begin
     if L < J then
       QuickSort(FList, L, J, Compare);
     L := I;
   end
   else
   begin
     if I < R then
       QuickSort(FList, I, R, Compare);
     R := J;
   end;
 until L >= R;
end;

嗯,原来调用了一个快排算法,算法中用到的比较两个元素的函数就是需要实现的函数。

再看源码

印象中,TStringList好像可以直接排序:

pascal 复制代码
procedure TStringList.Sort;
begin
  CustomSort(@StringListAnsiCompare);
end;  

procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
begin
  If (FCount>1) and (FForceSort or (FSortStyle<>sslAuto))  then
    begin
    Changing;
    QuickSort(0,FCount-1, CompareFn);
    Changed;
    end;
end;

嗯,同样是调用了一个快排算法,而且比较函数也是实现了的:

pascal 复制代码
function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
begin
  Result := List.DoCompareText(List.FList^[Index1].FString,
    List.FList^[Index].FString);
end;

function TStringList.DoCompareText(const s1, s2: string): PtrInt;
begin
  if FCaseSensitive then
  begin
    if UseLocale then
      result:=AnsiCompareStr(s1,s2)
    else
      result:=CompareStr(s1,s2);
  end else
  begin
    if UseLocale then
      result:=AnsiCompareText(s1,s2)
    else
      result:=CompareText(s1,s2);
  end;
end; 

原来如此!比较函数只要实现类似CompareTextCompareStr的效果就能被快排算法调用从而实现排序功能。

自己实现

由于json数组里的元素全部都是相同结构的json对象,那就简单粗暴点:

pascal 复制代码
function DefaltJsonCompare(Item1, Item2: Pointer): integer;
var
  s1, s2: string;
begin
  s1 := TJSONObject(Item1).Get('key', '');
  s2 := TJSONObject(Item2).Get('key', '');
  Result := CompareText(s1, s2);
end; 

测试一下,嗯,确实是期望的效果,完美收工!

总结

  1. 继承于TFPList的类,本质上都已实现了快排算法,也就是可以直接排序,所需要的仅仅是提供一个类似CompareText的比较函数的实现即可

  2. 基于TFPList组合并且以TFPList为主的类,也可以像TStringList一样封装一个方法实现排序,或者提供一个Helper实现排序

相关推荐
GoppViper5 天前
golang学习笔记17——golang使用go-kit框架搭建微服务详解
笔记·后端·学习·微服务·golang·编程语言·go-kit
GoppViper8 天前
golang学习笔记12——Go 语言内存管理详解
笔记·后端·学习·golang·编程语言·内存优化·golang内存管理
GoppViper8 天前
golang学习笔记11——Go 语言的并发与同步实现详解
笔记·后端·学习·golang·编程语言·goroutine·golang并发
一丝晨光9 天前
安全API
java·开发语言·c++·安全·编程·c·编程语言
GoppViper9 天前
golang学习笔记15——golang依赖管理方法
笔记·后端·学习·golang·编程语言·源代码管理·golang依赖管理
GoppViper11 天前
golang学习笔记10——golang 的 Gin 框架,快速构建高效 Web 应用
笔记·学习·golang·gin·编程语言
Geektec15 天前
智能代码编辑器:Visual Studio Code的深度剖析
vscode·编辑器·编程·代码编辑器·编程语言
股票程序交易接口19 天前
更适合编写股票盯盘软件或者量化交易平台的语言是Python还是C
量化交易·编程语言·股票api接口·股票量化接口·python股票接口
编程阿布20 天前
Python爬虫所需的技术及其原理(简单易懂)
开发语言·爬虫·python·编程语言
一丝晨光25 天前
Http/Https 请求慢的解决办法
开发语言·网络·网络协议·http·面试·https·编程语言