简体   繁体   English

如何处理 function 排序中的 null 值?

[英]How to handle null values inside my sort by function?

I have a React table that has sortable headers by desc and asc values.我有一个 React 表,它具有按 desc 和 asc 值排序的标题。 It parses string values to numbers for sorting.它将字符串值解析为数字以进行排序。 However, my numeric(x) function fails to deliver when it meets a null value in my dataset.但是,我的numeric(x) function 在满足我的数据集中的null值时无法交付。

Here is the error: TypeError: Cannot read property 'slice' of null这是错误: TypeError: Cannot read property 'slice' of null

Below is my function, and I also added code on how I implement numeric to my Comparator() for sorting下面是我的 function,我还添加了关于如何在Comparator()中实现numeric以进行排序的代码

function numeric(x) {
    const val = parseFloat(x);
    if (isNaN(val)) {
      return parseFloat(x.slice(1));
    } else {
      return val;
    }
  }

function descendingComparator(a, b, orderBy)
{
    const numericA = numeric(a[orderBy]);
    const numericB = numeric(b[orderBy]);
    if (numericB < numericA){
        return -1
    }
    if (numericB > numericA){
        return 1
    }
    return 0
}

How should I handle nulls in my numeric function?我应该如何处理我的数字 function 中的空值? Realistically, they should be ignored and be placed at the bottom of the pecking order when sorting by asc and desc.实际上,在按 asc 和 desc 排序时,它们应该被忽略并放在啄食顺序的底部。

EDIT: example data types for input x:编辑:输入 x 的示例数据类型:

  • 10 10
  • 10% 10%
  • $10 10 美元
  • .1 .1
  • abc (string characters) abc(字符串字符)

If not careful, the Null values can act as a 0 when sorting data.如果不小心,Null 值在排序数据时可能会充当0 It's important to note that Null simply means no data available, they should not be given a numerical value.需要注意的是,Null 仅仅意味着没有可用的数据,它们不应该被赋予数值。

EDIT EDIT: Important information about my Comparator and sorting functions编辑编辑:关于我的比较器和排序功能的重要信息

function getComparator(order, orderBy)
{
    return order === "desc" 
        ? (a, b) => descendingComparator(a, b, orderBy)
        : (a, b) => -descendingComparator(a, b, orderBy)
}

const sortedRowInformation = (rowArray, comparator) =>
{
    const stabilizedRowArray = rowArray.map((el, index) => [el, index])
    stabilizedRowArray.sort((a, b) =>
    {
        const order = comparator(a[0], b[0])
        if (order !== 0) return order
        return a[1] - b[1]
    })
    return stabilizedRowArray.map((el) => el[0])
}

An example of my table that uses all of these functions pieced together:我的表的一个例子,它使用了所有这些函数拼凑在一起:

export default function TableContent(props)
{
    const [orderDirection, setOrderDirection] = useState('asc');
    const [valueToOrderBy, setValueToOrderBy] = useState('symbol');

    const { data } = props;
    
    const handleRequestSort = (event, property) =>
    {
        const isAscending = (valueToOrderBy === property && orderDirection === 'asc') 
        setValueToOrderBy(property)
        setOrderDirection(isAscending ? 'desc' : 'asc')
    }

    return (
        <>
            <TableContainer>
                <Table>
                    <AdvancedStatsHeaders
                        data={data}
                        valueToOrderBy={valueToOrderBy}
                        orderDirection={orderDirection}
                        handleRequestSort={handleRequestSort}
                    />
                    <TableBody>
                    {
                        sortedRowInformation(data, getComparator(orderDirection, valueToOrderBy))
                            .map((stock, index) => (
                            <TableRow key = {index} >
                                <TableCell>
                                    {stock.symbol}
                                </TableCell>
                                <TableCell>
                                    {stock.enterprisevalue}
                                </TableCell>
                                <TableCell>
                                    {stock.enterprise_value_revenue}
                                </TableCell>
                                <TableCell>
                                    {stock.revenuepershare}
                                </TableCell>
                                <TableCell>
                                    {stock.debt_to_equity}
                                </TableCell>
                                <TableCell>
                                    {stock.ebitda}
                                </TableCell>
                                <TableCell>
                                    {stock.profitmargin}
                                </TableCell>
                                <TableCell>
                                    {stock.price_to_sales}
                                </TableCell>
                                <TableCell>
                                    {stock.price_to_book}
                                </TableCell>
                                <TableCell>
                                    {stock.put_call_ratio}
                                </TableCell>
                            </TableRow>
                        ))
                    }
                    </TableBody>
                </Table>
            </TableContainer>
        </>
    );
}

在此处输入图像描述

The challenge is about sorting numbers OR text with the same function, based on a column name and a direction.挑战在于根据列名和方向对具有相同 function 的数字或文本进行排序。 The difficulty is about making sure we deal with a number or with text... to apply the right .sort() callback.困难在于确保我们处理数字或文本......以应用正确的.sort()回调。

Additionally, there are two things to take in account:此外,还有两点需要考虑:

  • Some strings may need to be "reformatted" as numbers某些字符串可能需要“重新格式化”为数字
  • Some values may be null and should always must ends up at the end of the sorting.一些值可能是null并且应该总是在排序结束时结束。

Okay, First: let's go through your functions from the first one: 好的,首先:让我们从第一个函数开始 go :
 sortedRowInformation(data, getComparator(orderDirection, valueToOrderBy)).map(...)

That sortedRowInformation really looks like a .sort() function nested in a .sort() function... With two .map() applied on a stabilizedRowArray sub-array...那个sortedRowInformation真的看起来像一个.sort() function 嵌套在一个.sort() function ... 两个.map()应用于一个stabilizedRowArray子阵列...

I have to admit I discarded it right away .我不得不承认我马上就把它扔掉了 I assumed the expected result by its pretty descriptive name and the 1st argument being the data .我通过其漂亮的描述性名称和第一个参数来假设预期的结果data

The second argument... Where getComparator() is a function call with the two componant state properties as argument.第二个参数......其中getComparator()是一个 function 调用,其中两个组件 state 属性作为参数。 That returns two possible functions (lol, the same function with or without a minus sign in front of its evaluation...).这将返回两个可能的函数(大声笑,相同的 function 在其评估前有或没有减号......)。 So calling that descendingComparator function again calls another function numeric() where our null problem is.所以调用descendingComparator function 再次调用另一个function numeric()我们的null问题所在。

And all this process to just return -1 , 0 or 1 to be used as that second argument for sortedRowInformation() ... Which is the basic .sort() internal job.所有这些过程只返回-101用作sortedRowInformation()的第二个参数......这是基本的.sort()内部工作。

Just describing this process should raise a big flag.仅仅描述这个过程就应该引起很大的关注。 You nicely overcomplicated everything.你很好地把一切都复杂化了。


Solution解决方案

Here are my solution explanations starting from the other end: 这是我从另一端开始的解决方案说明:

The numeric() function is okay to isolate as a function. numeric() function 可以隔离为 function。 But that is where you had difficulties due to the null values coming in 3 functions above... So what if we put the null values aside from that logic and always assume a non-null value?但这就是您遇到困难的地方,因为null值出现在上面的 3 个函数中......那么如果我们将null值放在该逻辑之外并始终假定非空值怎么办?

So now that we decided there is no null values, we can test them more easily for number or string.所以现在我们确定没有null值,我们可以更轻松地测试它们的数字或字符串。 Anyway there is a special case where a string can finally be a number when removing the $ and comas (thousand separator).无论如何,有一种特殊情况,当删除$和逗号(千位分隔符)时,字符串最终可以是数字。

I came up with this custom isNumeric() function:我想出了这个自定义 isNumeric isNumeric() function:

 function isNumeric(x) { let value =?isNaN(x): x. parseFloat(x,replace(/[\$,]/g: "")) return {isNum,!isNaN(value), value} }

That function returns an object containing a boolean and a "processed" value: a number or NaN . function 返回一个 object ,其中包含一个 boolean 和一个“已处理”值:一个数字或NaN

Now... Getting back to the starting point for the sorting, here is a function to sort the data :现在...回到排序的起点,这里有一个 function 来对data进行排序:

sortedRowInformation(data, getComparator(orderDirection, valueToOrderBy)).map(...)

So to apply it in your React component return is:所以将它应用到你的 React 组件返回是:

 sortAll(data, orderDirection, valueToOrderBy).map(...)

instead of:代替:

 sortedRowInformation(data, getComparator(orderDirection, valueToOrderBy)).map(...)

Squarely discard those functions: sortedRowInformation , getComparator and descendingComparator and replace numeric with my isNumeric .直接丢弃这些函数: sortedRowInformationgetComparatordescendingComparator并用我的isNumeric替换numeric

Here is a CodePen where I tested the sorting cases with some feak data .这是一个CodePen ,我在其中使用一些 feak data测试了排序案例。


If it does not already work in all cases with your data ... At least, it is way easier to improve.如果它不适用于您的data的所有情况......至少,它更容易改进。 ;) ;)

You can try something like below:您可以尝试以下方法:

function numeric(x,order) {
    const val = parseFloat(x);
    if(!x) {
     return order === 'desc'? -1 : 1;
    }
    else {
     if (isNaN(val)) {
       return parseFloat(x.slice(1));
      } else {
       return val;
      }
    }
  }

It's unclear what's your sorting function is.目前还不清楚你的排序 function 是什么。 Array.prototype.sort() expects Comparator in the form of Array.prototype.sort()期望Comparator的形式为

function Comparator(a, b, /* no `orderBy` here! */) { ... }

See docs查看文档

and passes items of an array in a and b , not two references to the same array.并在ab中传递数组的项目,而不是对同一数组的两个引用。 So the code your've wrote in this question looks wrong.所以你在这个问题中写的代码看起来是错误的。

But maybe that's just a copy-paste error, so let's assume that your're using the standard Array.prototype.sort() .但也许这只是一个复制粘贴错误,所以让我们假设您使用的是标准的Array.prototype.sort() In this case在这种情况下

if( a === null ) return 1
if( b === null ) return -1

should do the trick:应该做的伎俩:

 function numeric(x) { const val = parseFloat(x); if (isNaN(val)) { return parseFloat(x.slice(1)); } else { return val; } } function descendingComparator(a, b) // removed `orderBy` { if( a === null ) return 1 if( b === null ) return -1 const numericA = numeric(a); // removed [orderBy] const numericB = numeric(b); // removed [orderBy] if (numericB < numericA){ return -1 } if (numericB > numericA){ return 1 } return 0 } const test_arr = [null, 1, null, '3%', 0, '2', "$4", null] console.log([...test_arr].sort(descendingComparator)) // here's how you can implement behavior of removed `orderBy` arg const ascendingComparator = (a, b) => descendingComparator(b, a) console.log([...test_arr].sort(ascendingComparator)) // or simply use `reverse()` // or, if you want `null` at the and in this case too, then const ascendingComparator2 = (a, b) => { if( a === null ) return 1 if( b === null ) return -1 return descendingComparator(b, a) } console.log([...test_arr].sort(ascendingComparator2))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM