i'm new in php, especially php array and i wanna learn more about array, i found this forum sound interesting to solve my problem.

i have some array like this :

Array
(
    [0] => Array
        (
            [0] => Printer_B //printer
            [1] => IDDHARMAHE //user
        )

    [1] => Array
        (
            [0] => Printer_B
            [1] => IDSIRIKINE
        )

    [2] => Array
        (
            [0] => Printer_C
            [1] => IDSUPRIY1
        )

    [3] => Array
        (
            [0] => Printer_A
            [1] => IDSUSANTEN
        )

    [4] => Array
        (
            [0] => Printer_A
            [1] => IDSUSANTEN
        )

    [5] => Array
        (
            [0] => Printer_B
            [1] => IDSEPTIATR
        )
}

and i want to produce array result like this

Array
(
	[Printer_A] => 1 //printer A is used by 1 user
	[Printer_B] => 3 //printer B is used by 3 user
	[Printer_C] => 1 //printer C is used by 1 user
}

what is the simple solution for this ? what php function should i used with this problem ?

because i want to count this array as fast as possible to reduce time.

many thanks before :)

Recommended Answers

All 12 Replies

What have you tried so far?

i have try this method and i dont feel this better way or still dirty code for me, and not fast enough to only count array value like that, and compare with my other array count values script (in different case), this is the worse count because it took so long time :( (almost 7x slowest than my other count array value script).

here my code :

// loop the printer array first
foreach( $arr_printer as $key_1 => $value_1 )
{
	//loop main array contain printer name and user
	foreach( $arr_user_printer as $key_2 => $value_2 )
	{
		//if printer name (from printer array) found in main array from value_2
		if (in_array($value_1, $value_2, true))
		{
			//create new array for this printer name, contain username
			//$value_2[1] = username
			$arr_user_in_printer[] = $value_2[1];
		}
	}
	
	if( is_array( $arr_user_in_printer ) )
	{
		//remove duplicate username
		$arr_user_in_printer = array_unique($arr_user_in_printer);

		//create final array
		//[printer_name] = total_usage
		$arr_printer_usage[$value_1] = count($arr_user_in_printer);
		
		//unset array, reset
		unset($arr_user_in_printer);
	}
	
}

$arr_printer_usage will show output like this :

Array
(
	[Printer_A] => 1	//printer A is used by 1 user
	[Printer_B] => 3	//printer B is used by 3 user
	[Printer_C] => 1	//printer C is used by 1 user
}

but it still not fast enough to proccessed because i have more than 100.000 data

$arr_printer contain data like this:

Array
(
	[0] => Printer_A
	[1] => Printer_B
	[2] => Printer_C
}

$arr_user_printer contain data like this :

Array
(
    [0] => Array
        (
            [0] => Printer_B
            [1] => IDDHARMAHE
        )

    [1] => Array
        (
            [0] => Printer_B
            [1] => IDSIRIKINE
        )

    [2] => Array
        (
            [0] => Printer_C
            [1] => IDSUPRIY1
        )

    [3] => Array
        (
            [0] => Printer_A
            [1] => IDSUSANTEN
        )

    [4] => Array
        (
            [0] => Printer_A
            [1] => IDSUSANTEN
        )

    [5] => Array
        (
            [0] => Printer_B
            [1] => IDSEPTIATR
        )
}

is there any simple solution for this ?

Well i'm going to assume you're using at least PHP 5, so look at this idea and lets see if we can't craft something that will speedup your results:

<?php

//Multidimensional array of printers.
//This can be ANY depth.
$printers = array(
	array('Printer_B', 'IDDHARMAHE'),
	array('Printer_B', 'IDSIRIKINE'),
	array('Printer_C', 'IDSUPRIY1'),
	array('Printer_A', 'IDSUSANTEN'),
	array('Printer_A', 'IDSUSANTEN'),
	array('Printer_B', 'IDSEPTIATR'),
);

//PrinterFilter class to filter our iterator and ONLY return values that start with Printer_
class PrinterFilter extends FilterIterator
{
	public function accept()
	{
		//Only accept values that start with Printer_
		if( false !== strpos(parent::current(), 'Printer_') ){
			return true;
		}
		return false;		
	}
}

//Create a new Iterator for the array
//Create a RecursiveArrayIterator around our array
//Create a RecursiveIteratorIterator around that so we can easily navigate it
//Create a PrintFilter interator around that so we can filter only values starting with Printer_
$iterator = new PrinterFilter( new RecursiveIteratorIterator( new RecursiveArrayIterator( $printers ) ) );

//Simply iterate over the iterator add new keys as necessary
//Increment existing keys.
$counts = array();
foreach( $iterator as $key => $value ){
	if( isset( $counts[$value] ) ){
		++$counts[$value];
	} else {
		$counts[$value] = 1;
	}
}

print_r($counts);
Array
(
    [Printer_B] => 3
    [Printer_C] => 1
    [Printer_A] => 2
)

thanks for the idea
yes i'm using latest php 5 from xampp package
but, in my data, printers name can be any name and not need to be filtered.
so how i can use your code ?

is just simply change to this ? :

$iterator = new RecursiveIteratorIterator( new RecursiveArrayIterator( $printers ) ) ;

Yes, if you're not filtering it for a specific value.

In the foreach loop, you can test $key or $value for anything you want to compile the counts etc.

i have an idea to change your filtering class (filtering from username characters)

from

//PrinterFilter class to filter our iterator and ONLY return values that start with Printer_
class PrinterFilter extends FilterIterator
{
	public function accept()
	{
		//Only accept values that start with Printer_
		if( false !== strpos(parent::current(), 'Printer_') ){
			return true;
		}
		return false;		
	}
}

to change that printer name is not started with characters : ID

can you help me again?
so, the array result still like this :

Array
(
    [Printer_B] => 3
    [Printer_C] => 1
    [Printer_A] => 2
)

many thanks again :)

PrintFilter extends the FilterIterator class which is part of the SPL in php.
http://php.net/manual/en/book.spl.php
http://www.php.net/manual/en/class.filteriterator.php

The accept function needs to return true or false. True meaning that it is a valid item to iterate over, false meaning we can disregard it. How you determine it returns true or false is entirely up to you.

In my example, i'm using the 'value' parent::current() of the array item to do my comparison. You could also use parent::key() to get the array key.

sorry my mistakes, i'm not pay attention from your result, i think it still normal count

from my question that the result should be

Array
(
	[Printer_A] => 1	//printer A is used by 1 user
	[Printer_B] => 3	//printer B is used by 3 user
	[Printer_C] => 1	//printer C is used by 1 user
}

because printers usage looks for how many "UNIQUE" users has been using that printer.
in my case, Printer_A has been used by two times, but this is only by 1 user

and its different from your result:

Array
(
    [Printer_B] => 3
    [Printer_C] => 1
    [Printer_A] => 2
)

i have solved your filtering solution, but still need the correct result like above.

i need your advice again...

does anyone has another solution for my problem ?

does anyone has another solution for my problem ?

can anyone help my problem here?
i'm still not solved this issue

Normally how I would approach this is make it work and then re-factor it into iterators etc. Since I've been so terribly busy the last few days I haven't had a chance to look at it again.

This should do what you wanted:

<?php

$printers = array(
	array('Printer_B', 'IDDHARMAHE'),
	array('Printer_B', 'IDSIRIKINE'),
	array('Printer_C', 'IDSUPRIY1'),
	array('Printer_A', 'IDSUSANTEN'),
	array('Printer_A', 'IDSUSANTEN'),
	array('Printer_B', 'IDSEPTIATR'),
);

class PrinterService
{
	public function getUsageByUniqueUser( array $printers )
	{
		$count = array();
		$uses = array();
		
		foreach( $printers as $use ){
			$uses[$use[0]][] = $use[1];
		}
		
		foreach( $uses as $key => $printer ){
			$printer = array_unique($printer);
			$count[$key] = count($printer);
		}
		
		return $count;
	}
}

$service = new PrinterService();
print_r($service->getUsageByUniqueUser($printers));
Array ( [Printer_B] => 3 [Printer_C] => 1 [Printer_A] => 1 )

Instead of the multiple loops there feels like there is a more efficient logic there, it just hasn't jumped out at me yet. Its also only single dimensional assuming that your array matches the array provided in structure. The keys are irrelevant.

Thanks mate, your PrinterService classes is the answer for my problem, and now is solved.
You are my hero today,,,
your php classes was run 6.9x faster than my first code as i want :)

sorry for my late to try your new php classes,i just modified my script with your php classes today when i opened this thread,this week i'm so busy with my works

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.