当属性是字符串时,如何按属性从左到右排序对象数组,首先具有数字?

Posted

技术标签:

【中文标题】当属性是字符串时,如何按属性从左到右排序对象数组,首先具有数字?【英文标题】:How to sort array of object by properties from left to right having numbers first when property is string? 【发布时间】:2020-05-09 04:38:18 【问题描述】:

我试图先按染色体然后按 startPosition 然后按 endPosition 对这个数组进行排序 这里的问题是属性是字符串类型,染色体包含 [1-22] 或 [x,y,m] 之间的数字

我已经根据一些 *** 答案创建了这个函数,它的作用是比较值并以这种方式对它们进行排序,但现在的问题是它是一个字符串排序,所以它将 10 放在 2 之前

    const sortByThenBy = (value, sortSettings) => 
    const sortIt = () => 
        const sortOrderBy = (left, right, sortOrder) => 
            const sortMultiplier = sortOrder === 'asc' ? 1 : -1;
            if (left > right) 
                return +1 * sortMultiplier;
            
            if (left < right) 
                return -1 * sortMultiplier;
            
            return 0;
        ;

        return (sortLeft, sortRight) => 
            const getValueByStr = (obj, path) => 
                let i;
                path = path.replace('[', '.');
                path = path.replace(']', '');
                path = path.split('.');
                for (i = 0; i < path.length; i++) 
                    if (!obj || typeof obj !== 'object') 
                        return obj;
                    
                    obj = obj[path[i]];
                
                return obj;
            ;

            return sortSettings
                .map(property =>
                    sortOrderBy(
                        getValueByStr(sortLeft, property.prop),
                        getValueByStr(sortRight, property.prop),
                        property.sortOrder
                    )
                )
                .reduceRight((left, right) => right || left);
        ;
    ;

    return value.sort(sortIt());
;
console.log(
    sortByThenBy(item, [
        
            prop: 'chromosome',
            numericSort: true,
            sortOrder: 'asc'
        ,
        
            prop: 'startPosition',
            sortOrder: 'asc'
        ,
        
            prop: 'endPosition',
            sortOrder: 'asc'
        
    ])
);

https://jsbin.com/kumavupuqi/edit?js,console,output

给定

    const item = [
     chromosome: '2', startPosition: '980000', endPosition: '989000' ,
     chromosome: '2', startPosition: '978000', endPosition: '979000' ,
     chromosome: '1', startPosition: '978000', endPosition: '979000' ,
     chromosome: '10', startPosition: '978000', endPosition: '979000' ,
     chromosome: 'x', startPosition: '978000', endPosition: '979000' 
];

预期结果

const item = [
 chromosome: '1', startPosition: '978000', endPosition: '979000' ,
 chromosome: '2', startPosition: '978000', endPosition: '979000' ,
 chromosome: '2', startPosition: '980000', endPosition: '989000' ,
 chromosome: '10', startPosition: '978000', endPosition: '979000' ,
 chromosome: 'x', startPosition: '978000', endPosition: '979000' 
];

【问题讨论】:

position 整数值的最大值是多少? @Ben 它在 1-22 或 X,Y,M 之间的任意位置表示染色体值,其他字段未知最大值。但我的目标是创建可以采用设置 obj 并在此基础上进行排序的函数,就像我在示例中所做的那样 【参考方案1】:

.sort 回调中,排序方式:

(1) 两者的染色体差为'y'

(2) 两者的染色体差为'x'

(3) 两项染色体的数值差

(4) 两个item的startPosition的数值差

(5) 两个item的endPosition的数值差

返回第一个为零的差:

const arr = [
   chromosome: '2', startPosition: '980000', endPosition: '989000' ,
   chromosome: '2', startPosition: '978000', endPosition: '979000' ,
   chromosome: '1', startPosition: '978000', endPosition: '979000' ,
   chromosome: '10', startPosition: '978000', endPosition: '979000' ,
   chromosome: 'x', startPosition: '978000', endPosition: '979000' ,
   chromosome: 'x', startPosition: '5', endPosition: '979000' ,
   chromosome: '1', startPosition: '978000', endPosition: '9999999' ,
];

arr.sort((a, b) => (
  ((a.chromosome === 'y') - (b.chromosome === 'y')) ||
  ((a.chromosome === 'x') - (b.chromosome === 'x')) ||
  (a.chromosome - b.chromosome) ||
  (a.startPosition - b.startPosition) ||
  (a.endPosition - b.endPosition)
));
console.log(arr);

- 隐含地将双方强制转换为数字,这一事实非常简洁。

另一种选择是创建一个函数,给定单个对象,该函数可以得出该对象的相对值(例如,在 1e20 处从 0 开始计算每个染色体差异,在 1e10 处从 0 开始计算每个 startPosition 差异,以及每个 endPosition与 0 在 1) 的差异。然后通过该函数传递两个对象并检查它们的相对值之间的差异:

const arr = [
   chromosome: '2', startPosition: '980000', endPosition: '989000' ,
   chromosome: '2', startPosition: '978000', endPosition: '979000' ,
   chromosome: '1', startPosition: '978000', endPosition: '979000' ,
   chromosome: '10', startPosition: '978000', endPosition: '979000' ,
   chromosome: 'x', startPosition: '978000', endPosition: '979000' ,
   chromosome: 'x', startPosition: '5', endPosition: '979000' ,
   chromosome: '1', startPosition: '978000', endPosition: '9999999' ,
];

const getVal = (obj) => 
  const chr = obj.chromosome;
  const chromVal = chr === 'y'
    ? 25
    : chr === 'x'
      ? 24
      : Number(chr);
  return (
    chromVal * 1e20 +
    obj.startPosition * 1e10 +
    Number(obj.endPosition)
  );
  return totalVal;
;

arr.sort((a, b) => getVal(a) - getVal(b));
console.log(arr);

【讨论】:

我最终使用了第一个解决方案,到目前为止似乎有效,但我不知道“-”【参考方案2】:

这可能会有所帮助。

染色体坐标所需的位数各不相同。我使用来自这里的信息:https://www.biostars.org/p/4355/ 来猜测 POSITION_DIGITS 的合理值。

此代码使用字符串比较。 javascript 不能精确表示任意大的整数。

const item = [
    chromosome: '2',
    startPosition: '980000',
    endPosition: '989000'
, 
    chromosome: '2',
    startPosition: '40',
    endPosition: '60'
, 
    chromosome: '1',
    startPosition: '978000',
    endPosition: '979000'
, 
    chromosome: '10',
    startPosition: '978000',
    endPosition: '979000'
, 
    chromosome: 'x',
    startPosition: '978000',
    endPosition: '979000'
];

const LETTERS =  x: '23', y: '24', m: '25' 
const CHROMOSOME_DIGITS = 2
const POSITION_DIGITS = 10

const toStr = (chromosome, startPosition, endPosition) => 
    ((LETTERS[chromosome] || chromosome.padStart(CHROMOSOME_DIGITS,'0')) + 
    startPosition.padStart(POSITION_DIGITS,'0') + 
    endPosition.padStart(POSITION_DIGITS,'0'))

console.log(item.sort((a,b) => toStr(a).localeCompare(toStr(b))))

【讨论】:

感谢您的回答和染色体的网站。我最终使用了CertainPerformance 第一个解决方案,但您的解决方案也有效。

以上是关于当属性是字符串时,如何按属性从左到右排序对象数组,首先具有数字?的主要内容,如果未能解决你的问题,请参考以下文章

如何在从左到右和从上到下排序的二维数组中搜索数字?

从左到右基数排序

在一个二维数组中,每一行都按照从左到右递增的顺序排序

从左到右移动声音

一分钟搞定基础排序算法——选择排序

在移动断点之后在angular-gridster2中从左到右排序gridster项目