簡體   English   中英

如何對復雜對象數組進行排序?

[英]How to sort an array of complex objects?

我有這種對對象數組進行排序的方法,但是當我有一個復雜的結構時,例如:

const data = [ { title: 'Book title', author: 'John', info: { language: english, pages: 500, price: '$50' }} ]

我無法排序 object 'info: {language: english, pages: 500, price:'$50'}'

我的代碼:

import { useMemo, useState } from 'react';

interface SortConfigProps {
  key: string;
  direction: string;
}

export const useSortableData = <T>(items: T[]) => {
  const [sortConfig, setSortConfig] = useState<SortConfigProps>(
    {} as SortConfigProps,
  );

  const sortedItems = useMemo(() => {
    const sortableItems = [...items];

    if (sortConfig) {
      sortableItems.sort((a: any, b: any) => {
        if (a[sortConfig.key] < b[sortConfig.key]) {
          return sortConfig.direction === 'ascending' ? -1 : 1;
        }
        if (a[sortConfig.key] > b[sortConfig.key]) {
          return sortConfig.direction === 'ascending' ? 1 : -1;
        }
        return 0;
      });
    }
    return sortableItems;
  }, [items, sortConfig]);

  const requestSort = (key: string) => {
    let direction = 'ascending';
    if (
      sortConfig &&
      sortConfig.key === key &&
      sortConfig.direction === 'ascending'
    ) {
      direction = 'descending';
    }
    setSortConfig({ key, direction });
  };

  return { items: sortedItems, requestSort, sortConfig };
};

您遇到的問題是 object 的深度克隆。擴展運算符僅深入 1 級,而您正在嘗試 go 兩級。 您可以使用來自 lodash 或其他深度克隆的庫。 我使用 JSON 技巧。

     const [data, setData] = useState(initData);
     function newArray() {
        return JSON.parse(JSON.stringify(data));
      }

示例顯示了兩個級別的排序: https://codesandbox.io/s/serverless-sea-jt220?file=/src/App.js

根據您的整體系統,有多種方法可以實現這一點,因此根據我的建議,我將假設以下內容:

  • 出於性能或某些其他原因,您希望保持數據原樣(即通過某種“標准化器”展平 object 不是一種選擇)。
  • 密鑰不能是 object,但必須是字符串
  • 您或用戶都可以設置密鑰。
  • 存在一個字符或一組字符,可以在鍵字符串中用作分隔符來構造鍵樹(例如'info.price'中的點,或'info->price'中的箭頭)。 定界符的一個重要屬性是在平面鍵中使用它是無效的(即在最后一個示例中不允許像data = [{ 'info->price': '$50' }]這樣的東西)

好的,現在你只需要實現一個訪問器來使用你的 object 上的復雜鍵,類似於Lodash.get 一個簡單的實現是這樣的:

const DELIMITER = '->';

function get(obj, key) {
  if (!obj) {
    // in case of null or undefined
    return obj;
  }
  if (!key) {
    // empty string or something like that
    return obj;
  }
  if (key.includes(DELIMITER)) {
    const keyComponents = key.split(DELIMITER);
    const firstKeyComponent = keyComponents.shift();
    const newKey = keyComponents.join(DELIMITER);
    return get(obj[firstKeyComponent], newKey)
  }
  return obj[key];
}

這里強調簡單,因為每次都重新計算keyComponents並不理想。 您可能還想為如何處理字符串或 arrays 添加額外的 if 情況,如果關鍵組件是數字,這些情況可能會導致問題。

編輯:也可以使用Object.prototype.hasOwnProperty檢查密鑰是否與內置的 Object function 相同,或者更好地檢查 obj 是否為 function 並決定如何處理該場景。

在你有了這個之后,你可以用這個替換你的代碼的比較部分:

  sortableItems.sort((a: any, b: any) => {
    const aValue = get(a, sortConfig.key);
    const bValue = get(b, sortConfig.key);
    if (aValue < bValue) {
      return sortConfig.direction === 'ascending' ? -1 : 1;
    }
    if (aValue] > bValue) {
      return sortConfig.direction === 'ascending' ? 1 : -1;
    }
    return 0;
  });

在大多數情況下,您可以撥打 go。 我不知道你的數據有多“狂野”,所以一定要測試一堆場景。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM