dongzhihong3940 2015-04-19 14:12
浏览 49

PHP / MySQL排序多维数组

I'm trying to sort an array in to a three-deep array. This is my current query:

SELECT * FROM question 
INNER JOIN category ON question.category_id = category.id
INNER JOIN difficulty ON question.difficulty_id = difficulty.id 

Expected result is something like:

array(
    '1' => array( // category id 1
        '1' => array( // difficulty id 1
            '1' => array('...'), // question id 1
            '2' => array('...') // question id 2
        ),
        '2' => array(
            '3' => array('...'),
            '4' => array('...')
        )
    )
)

I did have the following:

foreach($categories as $category) {
    foreach($difficulties as $difficulty) {
        foreach($questions as $question) {
            if ($question['category_id'] == $category['id'] && $question['difficulty_id'] == $difficulty['id']) {
                $feed[$category['id']][$difficulty['id']][$question['id']] = $question;
            }
        }
    }
}

But there will be 10,000+ questions and performance will be bad so is there a way I can do this with one query and fewer loops?

  • 写回答

1条回答 默认 最新

  • dongzong8110 2015-04-19 14:30
    关注

    Basically you could just return your query and order by the ids like so:

    Category_ID      Difficulty_ID      Question_ID
         0                0                 0
         0                0                 1
         1                0                 2
         1                3                 3
         1                3                 4
         2                0                 5
         2                1                 6
    

    Then parse everything in a while:

    1. each time the category_ID changes add a new category with empty difficulty and reset previous difficulty
    2. each time the difficulty changes add new difficulty to category with empty question
    3. each time add the question to current difficulty.

    To store this structure performantly in local storage:

    1. define a unique delimiter (note: IE doesn't support control characters, this also means you can't store binary data without encoding it before, e.g. base64)
    2. load each row of each table like this:

      key: unique table prefix + id
      value: columns (delimited with the delimiter defined before)
      

      The easiest way to return a whole table at once is to define a second delimiter and then have some slightly ugly query in the form of:

      SELECT id||delimiter||col1||delimiter||...||colN FROM ...
      

      And then put it all together with a list aggregation using the second delimiter (group_concat() in mysql).

    3. Sometimes you need maps (for N to M relations or also if you want to search questions by difficulty or category), but because each question only has one category and difficulty you are already done.

    Alternative

    If the data is not too big and doesn't change after login, then you can just use the application cache and echo your stuff in script tags.

    评论

报告相同问题?