如何在C#中复制Python的已排序内置函数的行为?

Mat*_*son 9 c# python sorting servicestack

我在Python中有一个字典列表.此列表作为Web服务之间的json传递.这些Web服务基于传递的json创建独特的签名.创建签名的一部分是规范化数据有效负载并确保所有内容都处于正确的顺序,所以我这样做(在Python中) - 工作正常.

data = [{'a': '1', 'b': '2', 'c': 3}, {'d': 3}, {3: 1}, {'100': '200'}]
sorted(data)
> [{3: 1}, {'100': '200'}, {'d': 3}, {'a': '1', 'c': 3, 'b': '2'}]
Run Code Online (Sandbox Code Playgroud)

现在,我需要在混合中添加一个C#应用程序,它需要能够创建与Python代码完全相同的签名.我没有发现以与Python的sorted内置函数相同的方式对上述数据结构进行排序的秘诀.

我正在使用ServiceStack来解析json数据.

我希望它会像做这样的事情一样容易(在C#中):

var jsonPayload = "[{\"a\": \"1\", \"b\": \"2\", \"c\": 3}, {\"d\": 3}, {3: 1}, {\"100\": \"200\"}]";                                                                        
var parsedJson = JsonArrayObjects.Parse(jsonPayload);                                                                                                                        
parsedJson.Sort();  
Run Code Online (Sandbox Code Playgroud)

但是,我从上面的C#代码中得到了这个例外:

`At least one object just implement IComparable`
Run Code Online (Sandbox Code Playgroud)

我理解为什么我会收到这个错误,但我不确定我应该怎么做.我真的希望我不必滚动自己的排序逻辑.我正在处理的实际数据非常动态.这只是阻止我向前发展的一个例子.

有没有人对如何在C#中使用类似sorted嵌套数据结构的python函数进行排序有任何建议或建议?

谢谢!

Ray*_*ger 0

如图所示,示例数据不是有效的 JSON。整数三不能是键,它必须是字符串。改成{3: 1}{"3": 1}

第二个问题是 C# 字典默认情况下不可排序。但是,您可以对它们进行子类化以使它们可排序。

Python2.x的字典排序算法是:

1)如果字典大小不同,则长度较短的为较小的值。

2) 如果大小相同,则扫描第一个字典以查找第一个字典中不存在或在第二个字典中具有不匹配值的最小键。不匹配的值决定哪个字典最大。

以下是 Python2.7 源代码中Objects/dictobject.c的相关摘录:

/* Subroutine which returns the smallest key in a for which b's value
   is different or absent.  The value is returned too, through the
   pval argument.  Both are NULL if no key in a is found for which b's status
   differs.  The refcounts on (and only on) non-NULL *pval and function return
   values must be decremented by the caller (characterize() increments them
   to ensure that mutating comparison and PyDict_GetItem calls can't delete
   them before the caller is done looking at them). */

static PyObject *
characterize(PyDictObject *a, PyDictObject *b, PyObject **pval)
{
    PyObject *akey = NULL; /* smallest key in a s.t. a[akey] != b[akey] */
    PyObject *aval = NULL; /* a[akey] */
    Py_ssize_t i;
    int cmp;

    for (i = 0; i <= a->ma_mask; i++) {
        PyObject *thiskey, *thisaval, *thisbval;
        if (a->ma_table[i].me_value == NULL)
            continue;
        thiskey = a->ma_table[i].me_key;
        Py_INCREF(thiskey);  /* keep alive across compares */
        if (akey != NULL) {
            cmp = PyObject_RichCompareBool(akey, thiskey, Py_LT);
            if (cmp < 0) {
                Py_DECREF(thiskey);
                goto Fail;
            }
            if (cmp > 0 ||
                i > a->ma_mask ||
                a->ma_table[i].me_value == NULL)
            {
                /* Not the *smallest* a key; or maybe it is
                 * but the compare shrunk the dict so we can't
                 * find its associated value anymore; or
                 * maybe it is but the compare deleted the
                 * a[thiskey] entry.
                 */
                Py_DECREF(thiskey);
                continue;
            }
        }

        /* Compare a[thiskey] to b[thiskey]; cmp <- true iff equal. */
        thisaval = a->ma_table[i].me_value;
        assert(thisaval);
        Py_INCREF(thisaval);   /* keep alive */
        thisbval = PyDict_GetItem((PyObject *)b, thiskey);
        if (thisbval == NULL)
            cmp = 0;
        else {
            /* both dicts have thiskey:  same values? */
            cmp = PyObject_RichCompareBool(
                                    thisaval, thisbval, Py_EQ);
            if (cmp < 0) {
                Py_DECREF(thiskey);
                Py_DECREF(thisaval);
                goto Fail;
            }
        }
        if (cmp == 0) {
            /* New winner. */
            Py_XDECREF(akey);
            Py_XDECREF(aval);
            akey = thiskey;
            aval = thisaval;
        }
        else {
            Py_DECREF(thiskey);
            Py_DECREF(thisaval);
        }
    }
    *pval = aval;
    return akey;

Fail:
    Py_XDECREF(akey);
    Py_XDECREF(aval);
    *pval = NULL;
    return NULL;
}

static int
dict_compare(PyDictObject *a, PyDictObject *b)
{
    PyObject *adiff, *bdiff, *aval, *bval;
    int res;

    /* Compare lengths first */
    if (a->ma_used < b->ma_used)
        return -1;              /* a is shorter */
    else if (a->ma_used > b->ma_used)
        return 1;               /* b is shorter */

    /* Same length -- check all keys */
    bdiff = bval = NULL;
    adiff = characterize(a, b, &aval);
    if (adiff == NULL) {
        assert(!aval);
        /* Either an error, or a is a subset with the same length so
         * must be equal.
         */
        res = PyErr_Occurred() ? -1 : 0;
        goto Finished;
    }
    bdiff = characterize(b, a, &bval);
    if (bdiff == NULL && PyErr_Occurred()) {
        assert(!bval);
        res = -1;
        goto Finished;
    }
    res = 0;
    if (bdiff) {
        /* bdiff == NULL "should be" impossible now, but perhaps
         * the last comparison done by the characterize() on a had
         * the side effect of making the dicts equal!
         */
        res = PyObject_Compare(adiff, bdiff);
    }
    if (res == 0 && bval != NULL)
        res = PyObject_Compare(aval, bval);

Finished:
    Py_XDECREF(adiff);
    Py_XDECREF(bdiff);
    Py_XDECREF(aval);
    Py_XDECREF(bval);
    return res;
}
Run Code Online (Sandbox Code Playgroud)