H2O -> H2 + O2
I converted the previous string into two arrays :
Array ( [0] => H2 [1] => O2 )
Array ( [0] => H2O )
I also created another array from the string which gets all the elements in the reaction
Array ( [0] => H [1] => O )
what I am trying to do is get the number beside the element and make an array from it. In this case, I am trying to achieve something like this :
array to find the number beside the H in the equation
Array ( [0] => 2 [1] => 0 )
Array ( [0] => 2 )
array to find the number beside the O in the equation
Array ( [0] => 0 [1] => 2 )
Array ( [0] => 1 )
which is basically demonstrated in this table :
H2 + O2 -> H2O
H: 2 0 2
O: 0 2 1
How can I achieve such a thing. I am trying to create a chemical balancer and I am stuck in this step.
more advanced question.. when searching for an element what if there you have an element like this : Ba(NO3)2 how can you account for 2 Nitrogens and 6 oxygens when creating the array.
<?php
function chemistry($arr)
{
$result = array();
array_walk($arr, function($value) use (&$result)
{
preg_match_all("#([A-Z][a-z]*)(\d*)#", $value, $match);
$formula = array_combine($match[1],
array_map(function($val)
{
if(intval($val) == 0)
return "1";
else
return $val;
}, $match[2]));
if(count($formula) == 1)
{
$result[$match[1][0]] = $formula[$match[1][0]];
}
else
$result = $formula;
});
return $result;
}
$left = array("H2", "O2");
$right = array("H2O");
print_r(chemistry($right));
print_r(chemistry($left));
Output:
Array # for H2O
(
[H] => 2
[O] => 1
)
Array # for H2, O2
(
[H] => 2
[O] => 2
)
I am interested to solve your problem, however I try to solve it using OOP. First of all, one should model the data structure to work with. Therefore, the problem could be solved clearly.
Here is my working code (it requires PHP >= 5.3):
<?php
$h2 = Element::fromString('H2');
//var_dump($h2->getName()); // H
//var_dump($h2->getNumber()); // 2
$o2 = Element::fromString('O2');
//var_dump($o2->getName()); // O
//var_dump($o2->getNumber()); // 2
$h2o = ElementGroup::fromString('H2O');
foreach ($h2o->getElements() as $element) {
var_dump($element->getName());
var_dump($element->getNumber());
}
// this should print :
// H
// 2
// O
// 1
/* element for H2 or O2 */
class Element
{
/* example : H */
private $name;
/* example : 2 */
private $number;
public function __construct($name, $number = 0)
{
$this->name = $name;
$this->number = $number;
}
public function getName()
{
return $this->name;
}
public function getNumber()
{
return $this->number;
}
public static function fromString($string)
{
preg_match('/([a-zA-Z])(\d*)/', $string, $matches);
$element = new self($matches[1], ($matches[2] != '') ? (int)$matches[2] : 1);
return $element;
}
}
/* H2O */
class ElementGroup
{
private $elements = array();
public function addElement(Element $element)
{
$this->elements[] = $element;
}
public function getElements()
{
return $this->elements;
}
public static function fromString($string)
{
preg_match_all('/[a-zA-Z]\d*/', $string, $matches);
$elementGroup = new self();
if (!empty($matches)) {
foreach ($matches[0] as $elementString) {
$elementGroup->addElement(Element::fromString($elementString));
}
}
return $elementGroup;
}
}
Try this:
function make(array $arr, $fullName) {
$struct = array(
$fullName => array()
);
foreach ($arr as $item) {
$atomAmount = preg_replace('/[^0-9]/', '', $item);
$atomName = str_replace($atomAmount, '', $item);
$struct[$fullName][$atomName] = (int) $atomAmount;
}
return $struct;
}
make(array('H2', 'O2'), 'H2O');
This function returns:
array (size=1)
'H2O' =>
array (size=2)
'H' => int 2
'O' => int 2
I think this structure of an array is better.