up vote 1 down vote favorite
share [fb]

I hope anyone can help me to fix a little problem. After getting a clear mind I still stuck and can't find a solution. I guess it is something obviously simple.

I stuck to an array structure and need to sort them. Here is a small example of the array:

$brand["BRAND_1"]["name"] = 'Brand Name 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['name'] = 'Headline Subbrand 2';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['text'] = 'text for Subbrand 2';

$brand["BRAND_2"]["name"] = 'Brand Name 2';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';

There could be n amount of BRAND_N and n amount of SUB_BRAND_N.

I have an order ID which stucks to a flexible order:

0 = out as in (dont worry about this, catch it at an earlier stage)
1 = BRAND_1.SUB_BRAND_1
2 = BRAND_1.SUB_BRAND_2
3 = BRAND_2.SUB_BRAND_1

This gets extended if there are more as these four cases and the order itself could change. So I have to work with the IDs.

The order should change the position in the array and push the value of the Id to the top in the array, for example:

order id = 2:

$brand["BRAND_1"]["name"] = 'Brand Name 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['name'] = 'Headline Subbrand 2';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['text'] = 'text for Subbrand 2';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';

$brand["BRAND_2"]["name"] = 'Brand Name 2';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';

order id = 3:

$brand["BRAND_2"]["name"] = 'Brand Name 2';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';

$brand["BRAND_1"]["name"] = 'Brand Name 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['name'] = 'Headline Subbrand 2';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['text'] = 'text for Subbrand 2';

I have tried this so far:

<?php

$order[1] = 'BRAND_1::SUB_BRAND_1';
$order[2] = 'BRAND_1::SUB_BRAND_2';
$order[3] = 'BRAND_2::SUB_BRAND_1';

// for testing
$orderId = 2;

// get the brand and sub_brand
$part = explode("::", $order[$orderId]); 

// set the new brand list
$newBrand[$part[0]]['name'] = $brand[$part[0]]['name'];
$newBrand[$part[0]]['list'][$part[1]] = $brand[$part[0]]['list'][$part[1]];

// unset the brand which should be first of the main brand array
unset($brand[$part[0]]['list'][$part[1]]);

// if there was only one list unset the whole brand part
if( count($brand[$part[0]]['list']) < 1 ) {
    unset( $brand[$part[0]] );
}

Now I have two arrays:

$brand includes the whole brands except this one which should be the first

$newBrand includes only this brand which should be at the top

Now I just need to add $brand to $newBrand but there is my problem :) Tried a lot of different ways from rebuilding the array to push the content, replace or merge... but I always run in circles.

Any other idea, shorter code, better approach..?

I wrote the whole code into codepad.org for better testing: Codepad example

Any help or suggestion appreciated.

Cheers!

EDIT:

Sorry for the misunderstanding:

The order is a specification outside the code. The aim is to set one element depending on the orderId to the top in the $brand array. The $orderId will get passed by POST, GET or a class call.

The $order array is just an array which helps me to make the specification accessible in the code.

So the $orderId match one element of the $order array and will return this element which should be on the top of the $brand array. Due to the fact that there is no numeric keys I decide to use the "brand::sub_brand" syntax to access on both depth level.

Hope this explains it a litte better.

Thanks

link|improve this question

Order ID determines only the first element, other elements will be ordered as specified in order IDs array, right? – galymzhan Sep 30 '11 at 3:59
Can you clarify: You HAVE to use the array structure from the beginning? Are you saying that the sort can change? If so, where are you getting your sort instructions? – Shad Sep 30 '11 at 4:00
*update and hope this answers your questions – Talisin Sep 30 '11 at 4:14
feedback

1 Answer

up vote 1 down vote accepted

Here is one possible solution (test it here):

<?php

function getOrderingRules()
{
    return array(
        1 => 'BRAND_1.SUB_BRAND_1',
        2 => 'BRAND_1.SUB_BRAND_2',
        3 => 'BRAND_2.SUB_BRAND_1',
    );
}

function getOrderedBrands($brands, $orderId)
{
    $rules = getOrderingRules();
    if (!isset($rules[$orderId])) {
        throw new RuntimeException("Rule for order id '$orderId' is not specified");
    }

    $result = array();

    // Push the first element
    list($key, $subkey) = explode('.', $rules[$orderId]);
    $result[$key] = array(
        'name' => $brands[$key]['name'],
        'list' => array(
            $subkey => $brands[$key]['list'][$subkey],
        ),
    );

    // Push remaining elements in the order they appear in $rules
    foreach ($rules as $oid => $rule) {
        // Skip order id of the first element
        if ($oid == $orderId) {
            continue;
        }
        list($key, $subkey) = explode('.', $rules[$oid]);
        if (!isset($result[$key])) {
            $result[$key] = array(
                'name' => $brands[$key]['name'],
                'list' => array(),
            );
        }
        $result[$key]['list'][$subkey] = $brands[$key]['list'][$subkey];
    }

    return $result;
}

// Loading all brands (could be external source, like database)
$brand["BRAND_1"]["name"] = 'Brand Name 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['name'] = 'Headline Subbrand 2';
$brand["BRAND_1"]["list"]['SUB_BRAND_2']['text'] = 'text for Subbrand 2';

$brand["BRAND_2"]["name"] = 'Brand Name 2';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['name'] = 'Headline Subbrand 1';
$brand["BRAND_2"]["list"]['SUB_BRAND_1']['text'] = 'text for Subbrand 1';

// Sort and output
print_r(getOrderedBrands($brand, 1));
print_r(getOrderedBrands($brand, 2));
print_r(getOrderedBrands($brand, 3));

You should be aware that with this array structure ($brands) you won't be able to set ordering rules like this:

1 = BRAND_1.SUB_BRAND_1
2 = BRAND_2.SUB_BRAND_1
3 = BRAND_1.SUB_BRAND_2

because once you met element keyed by BRAND_1, you have to iterate over all of it's sub-brands. If you don't have such rules, everything is fine. Otherwise you have to store sorted array structured like this (because actually you are sorting sub-brands, not brands):

$subBrands = array(
    array(
        'name' => 'Headline Subbrand 1',
        'text' => 'Text for it',
        'parent' => 'BRAND_1',
        'key' => 'SUB_BRAND_1',
    ),
    array(
        'name' => 'Headline Subbrand 2',
        'text' => 'Text for it',
        'parent' => 'BRAND_1',
        'key' => 'SUB_BRAND_2',
    ),
);
$parentBrands = array(
    'BRAND_1' => 'Brand Name 1',
    'BRAND_2' => 'Brand Name 2',
);

Then you can sort $subBrands and iterate over it

link|improve this answer
Thats awesome. There wont be a rule to mix up the sub_brands. So your solution works perfect. And I also figured out where my failure was. Thanks dude! – Talisin Sep 30 '11 at 5:05
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.