Avoid nested loops in PHP and Python

Avoid nested loop notation by using generators in PHP and Python

When decoding and using JSON as shown below, loop processing may be described by nesting.

nest.json


{
  "a": {"A": {"A0": [1, 2], "A1": [3, 4]}, "B": {"A0": [5, 6], "A1": [7, 8]}},
  "b": {"A": {"A0": [10, 20], "A1": [30, 40]}, "B": {"A0": [50, 60], "A1": [70, 80]}}
}

At this time, the value extraction of the index 1 of the key ʻA0` has the following result, but when realizing the processing with PHP or Python, there are cases where it becomes a double loop or a triple loop.

[2, 6, 20, 60]

Since a generator using yield from is available in PHP7 and Python3.3 or later, use this function to verify whether you can break out of the nested loop. For verification, PHP 7.1.5 and Python 3.5.0 are used.

When realized by a nested loop

The PHP and Python code is described as an example when it is realized by triple loop and double loop.

For PHP7

ʻAssuming that array_walketc. is not used, it is implemented only withforeach`.

<?php

$nest = json_decode(file_get_contents("nest.json"), true);

/*
$nest = [
  "a" => ["A" => ["A0" => [1,2], "A1" => [3,4]], "B" => ["A0" => [5,6], "A1" => [7,8]]],
  "b" => ["A" => ["A0" => [10,20], "A1" => [30,40]], "B" => ["A0" => [50,60], "A1" => [70,80]]]
];
*/

$r = [];
foreach ($nest as $v1) {
    foreach ($v1 as $v2) {
        foreach ($v2 as $k => $v3)  {
            if ($k === "A0") {
                $r[] = $v3[1];
            }
        }
    }
}
print_r($r);

$r = [];
foreach ($nest as $v1) {
    foreach ($v1 as $v2) {
        if (isset($v2["A0"][1]))  {
            $r[] = $v2["A0"][1];
        }
    }
}
print_r($r);

For Python 3

Writing almost the same as PHP.

import json
from collections import OrderedDict

nest = json.load(open("nest.json"), object_pairs_hook=OrderedDict)

"""
nest = {
  "a": {"A": {"A0": [1,2], "A1": [3,4]}, "B": {"A0": [5,6], "A1": [7,8]}},
  "b": {"A": {"A0": [10,20], "A1": [30,40]}, "B": {"A0": [50,60], "A1": [70,80]}}
}
"""

r = []
for v1 in nest.values():
    for v2 in v1.values():
        for k, v3 in v2.items():
            if k == "A0" and len(v3) > 1:
                r.append(v3[1])
print(r)

r = []
for v1 in nest.values():
    for v2 in v1.values():
        if "A0" in v2 and len(v2["A0"]) > 1:
            r.append(v2["A0"][1])
print(r)

When realized with yield from

Both PHP and Python can be written in the same way.

For PHP7

It will be relatively simple. There is no need to add loop processing even if the array hierarchy becomes deeper.

<?php

$nest = json_decode(file_get_contents("nest.json"), true);

function zslice ($n)
{
     foreach($n as $k => $v) {
         yield from $v;
     }
}

$r = [];
foreach(zslice(zslice($nest)) as $k => $v) {
    if ($k == "A0") {
        $r[] = $v[1];
    }
}
print_r($r);

$r = [];
foreach(zslice($nest) as $k => $v) {
    if (isset($v["A0"][1])) {
        $r[] = $v["A0"][1];
    }
}
print_r($r);

For Python 3

Since it is handled by dict, a little complicated processing is required, but basically it is the same implementation method as PHP7.

import json
from collections import OrderedDict

nest = json.load(open("nest.json"), object_pairs_hook=OrderedDict)


def zslice(n):
    r = n.values() if isinstance(n, dict) else n
    for v in r:
        if isinstance(v, dict):
            d = v.items()
        elif isinstance(v, tuple) and len(v) > 1:
            d = v[1].items()
        else:
            raise ValueError
        yield from d

r = []
for k, v in zslice(zslice(nest)):
    if k == "A0" and len(v) > 1:
        r.append(v[1])
print(r)

r = []
for k, v in zslice(nest):
    if "A0" in v and len(v["A0"]) > 1:
       r.append(v["A0"][1])
print(r)

Other

It may be simpler and easier to read by separating the zslice as shown below.

import json
from collections import OrderedDict

nest = json.load(open("nest.json"), object_pairs_hook=OrderedDict)


def zslice1(n):
    for v in n.values():
        yield from v.items()


def zslice2(n):
    for k, v in n:
        yield from v.items()

r = []
for k, v in zslice2(zslice1(nest)):
    if k == "A0" and len(v) > 1:
        r.append(v[1])
print(r)

r = []
for k, v in zslice1(nest):
    if "A0" in v and len(v["A0"]) > 1:
       r.append(v["A0"][1])
print(r)

Output result

The output result of PHP and Python sample code described here is described.

For PHP

python


Array
(
    [0] => 2
    [1] => 6
    [2] => 20
    [3] => 60
)
Array
(
    [0] => 2
    [1] => 6
    [2] => 20
    [3] => 60
)

For Python

Output result


[2, 6, 20, 60]
[2, 6, 20, 60]

Supplement: About the order of Python dictionaries

If ʻobject_pairs_hook = OrderedDict is not specified in the second argument of json.load`, the order of the elements may be different if the sample is executed several times.

pattern 1


[60, 20, 6, 2]
[60, 20, 6, 2]

Pattern 2


[6, 2, 60, 20]
[6, 2, 60, 20]

Since the order of elements is not guaranteed when creating dict, use ʻOrderedDict` to maintain consistency.

Recommended Posts

Avoid nested loops in PHP and Python
Avoid multiple loops in Python
POST JSON in Python and receive it in PHP
Stack and Queue in Python
Avoid KeyError in python dictionary
Unittest and CI in Python
A simple way to avoid multiple for loops in Python
MIDI packages in Python midi and pretty_midi
Difference between list () and [] in Python
Difference between == and is in python
View photos in Python and html
Sorting algorithm and implementation in Python
Manipulate files and folders in Python
About dtypes in Python and Cython
Assignments and changes in Python objects
Check and move directories in Python
Ciphertext in Python: IND-CCA2 and RSA-OAEP
Hashing data in R and Python
Function synthesis and application in Python
Export and output files in Python
Compare Python and JavaScript array loops
Reverse Hiragana and Katakana in Python2.7
Reading and writing text in Python
[GUI in Python] PyQt5-Menu and Toolbar-
Create and read messagepacks in Python
Overlapping regular expressions in Python and Java
Differences in authenticity between Python and JavaScript
Notes using cChardet and python3-chardet in Python 3.3.1.
Differences between Ruby and Python in scope
AM modulation and demodulation in Python Part 2
difference between statements (statements) and expressions (expressions) in Python
Eigenvalues and eigenvectors: Linear algebra in Python <7>
Implementation module "deque" in queue and Python
Line graphs and scale lines in python
Obtaining temporary AWS credentials in PHP, Python
Implement FIR filters in Python and C
Differences in syntax between Python and Java
Check and receive Serial port in Python (Port check)
Difference between PHP and Python finally and exit
Search and play YouTube videos in Python
Difference between @classmethod and @staticmethod in Python
Decorator to avoid UnicodeEncodeError in Python 3 print ()
Difference between append and + = in Python list
Difference between nonlocal and global in Python
Write O_SYNC file in C and Python
Dealing with "years and months" in Python
Read and write JSON files in Python
Easily graph data in shell and Python
Private methods and fields in python [encryption]
Find and check inverse matrix in Python
Linear Independence and Basis: Linear Algebra in Python <6>
Call sudo in Python and autofill password
Differences in multithreading between Python and Jython
Module import and exception handling in python
How to use is and == in Python
Project Euler # 1 "Multiples of 3 and 5" in Python
Python in optimization
CURL in python
Metaprogramming in Python
Python 3.3 in Anaconda
Organize python modules and packages in a mess