Metadata-Version: 2.4
Name: py-lexorank
Version: 1.0.2
Summary: Lightweight, dependency-free Python implementation of LexoRank algorithm for fractional indexing
Author-email: ixfcao <2717176337@qq.com>
License: MIT License
        
        Copyright (c) 2026 Your Name
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
Project-URL: Homepage, https://github.com/ixfcao/lexorank-py
Project-URL: Repository, https://github.com/ixfcao/lexorank-py
Project-URL: Documentation, https://github.com/ixfcao/lexorank-py#readme
Keywords: lexorank,sorting,indexing,database,ordering,fractional-indexing,rebalancing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Dynamic: license-file

# LexoRank Python工具库

lexorank-py是用于分数索引的lexorank算法的轻量级、无依赖性的Python实现，实现了高效的拖放排序、动态列表重新排序和插入任何位置的操作，而无需完全重新平衡列表。
非常适合构建可排序的任务列表、看板、脚本编辑器或任何需要持久、稳定排序键的UI。

## 目录结构

```
py-lexorank/
├── src/py_lexorank/              # Python import 包：py_lexorank
│   ├── __init__.py
│   ├── lexorank_key.py           # 业务层 API（推荐使用）
│   └── lexorank/                 # LexoRank 核心实现（算法层）
│       ├── __init__.py
│       ├── lexo_decimal.py
│       ├── lexo_integer.py
│       ├── lexo_rank.py
│       ├── lexo_rank_bucket.py
│       └── numeral_systems.py
├── examples/                     # 示例/造排序数据脚本（不随 pip 包发布）
│   └── demo.py
├── tests/                        # 单元测试
│   └── test_lexorank.py
├── pyproject.toml
└── README.md
```

## 项目概述

LexoRank 是一种排序算法，允许在列表中任意位置插入新元素而无需重新排列整个列表。它通过在两个已存在的排序键之间生成新的排序键来实现这一点。

### 核心概念

- **排序键（Rank Key）**：用于数据库排序的字符串，按字典序排序即可得到正确的顺序
- **分数索引（Fractional Indexing）**：在两个排序键之间生成新键的技术
- **分桶（Bucket）**：用于隔离不同分组的排序空间，避免 rank 过度变长
- **进制系统**：使用 base36 进制系统进行数值表示

## 使用方法

### 基础安装和使用


## 安装

使用 pip 安装：
```bash
pip install py-lexorank
```

或使用 uv (更快的包管理器)：
```bash
uv pip install py-lexorank
```

推荐直接导入 `LexoRankKey` 类即可开始使用：

```python
from py_lexorank import LexoRankKey

# 初始化空列表的第一条记录
first_rank = LexoRankKey.init_for_empty_list()

# 在两条记录之间插入
second_rank = LexoRankKey.insert_after(first_rank)
middle_rank = LexoRankKey.insert_between(first_rank, second_rank)

# 插入到最前面
before_first = LexoRankKey.insert_before(first_rank)

# 通用插入接口
new_rank = LexoRankKey.insert(prev_rank, next_rank)
```

### 常见使用场景

#### 1. 空列表插入第一条记录
```python
# 当列表为空时，插入第一条记录
first_rank = LexoRankKey.init_for_empty_list()
```

#### 2. 追加到列表末尾
```python
# 在现有列表末尾追加新记录
new_rank = LexoRankKey.insert_after(last_rank)
```

#### 3. 在两条记录之间插入
```python
# 在两个已知记录之间插入新记录（常用：拖拽排序）
new_rank = LexoRankKey.insert_between(left_rank, right_rank)
```

#### 4. 插入到列表开头
```python
# 在列表开头插入新记录
new_rank = LexoRankKey.insert_before(first_rank)
```

#### 5. 通用插入接口
```python
# 最灵活的插入方式，适用于所有场景
new_rank = LexoRankKey.insert(prev_rank, next_rank)
```

### 查看 API 文档（命令行）

本项目不发布任何 CLI（避免与业务 API 混淆）。你可以用命令行查看 API 文档：

```bash
# 查看模块文档（包含 LexoRankKey 的说明和方法注释）
python -m pydoc py_lexorank.lexorank_key

# 或在交互式环境查看类帮助
python -c "from py_lexorank import LexoRankKey; help(LexoRankKey)"
```

### 演示脚本

运行演示脚本来查看各种使用场景：

1. 直接运行（默认空列表自动插入第一条）
```bash
PYTHONPATH=src python examples/demo.py
```
2. 指定批量生成数量（默认空列表自动插入第一条，根据生成的第一条一次生成 X 个递增 rank）
```bash
PYTHONPATH=src python examples/demo.py --count 20
```
3. 指定起始 rank（从某个已有 rank 后面开始批量生成X 个递增 rank）
注意：rank 里有 |，在 zsh 里必须用引号包起来
```bash
PYTHONPATH=src python examples/demo.py --start '0|hzzzzz:' --count 10
```

## 测试

在仓库根目录运行：

```bash
PYTHONPATH=src python -m unittest discover -s tests -v
```

## 文件详细说明

源码位于 `src/py_lexorank/`：

- `src/py_lexorank/lexorank_key.py`：业务层 API（字符串进出，推荐）
- `src/py_lexorank/lexorank/`：LexoRank 算法核心实现与 CLI
- `examples/demo.py`：示例/造排序数据脚本（repo-only）
- `tests/test_lexorank.py`：单元测试

## 业务场景应用

### 1. 任务列表排序

在项目管理应用中，用户经常需要调整任务的顺序。使用 LexoRank 可以避免每次重排都更新整个列表：

```python
from py_lexorank.lexorank_key import LexoRankKey

# 创建新任务并插入到列表中
def add_task_after(task_list, target_task_id):
    target_task = get_task(target_task_id)
    next_task = get_next_task(target_task_id)
    
    new_rank = LexoRankKey.insert_between(target_task.rank, next_task.rank)
    create_task(rank=new_rank)
```

### 2. 菜单项排序

在菜单编辑器中，用户可以通过拖拽调整菜单项的顺序：

```python
from lexorank_key import LexoRankKey

# 拖拽排序：将项目从 old_pos 移动到 new_pos
def move_menu_item(item_id, old_pos, new_pos):
    if new_pos == 0:  # 移到开头
        new_rank = LexoRankKey.insert_before(get_first_item().rank)
    elif new_pos == get_last_position():  # 移到末尾
        new_rank = LexoRankKey.insert_after(get_last_item().rank)
    else:  # 移到中间
        prev_item = get_previous_item(new_pos)
        next_item = get_next_item(new_pos)
        new_rank = LexoRankKey.insert_between(prev_item.rank, next_item.rank)
    
    update_item_rank(item_id, new_rank)
```

### 3. 场景排序

在视频制作应用中，用户可以对场景进行排序：

```python
from lexorank_key import LexoRankKey

def reorder_scenes(scene_ids, new_order):
    """根据新顺序重新排列场景"""
    ordered_scenes = []
    for i, scene_id in enumerate(new_order):
        if i == 0:
            # 第一个场景使用初始 rank 或者基于第一个现有场景的 rank
            if len(ordered_scenes) > 0:
                rank = LexoRankKey.insert_before(ordered_scenes[0].rank)
            else:
                rank = LexoRankKey.init_for_empty_list()
        else:
            # 后续场景插入到前一个场景之后
            rank = LexoRankKey.insert_after(ordered_scenes[-1].rank)
        
        ordered_scenes.append(Scene(id=scene_id, rank=rank))
    
    # 批量更新所有场景的 rank
    bulk_update_scene_ranks(ordered_scenes)
```

## 注意事项

### 并发安全

当多个请求并发向同一缝隙插入时，可能会生成重复的 rank。建议：

1. 在数据库中设置唯一约束
2. 在业务层添加适当的锁或重试机制
3. 处理插入冲突的情况

### 性能考虑

- LexoRank 字符串会随着频繁的插入操作逐渐变长
- 当 rank 字符串变得过长时，可能需要执行重新编号操作
- 对于大量数据的排序，定期进行碎片整理是有益的

## 测试

运行单元测试验证功能：

```bash
python -m lexorank.test_lexorank
```

或直接运行测试文件：

```bash
python lexorank/test_lexorank.py
```

## 许可证

本项目遵循 MIT 许可证。
