PHP ассоциативный многомерный массив - печатать только выбранные ключи - PullRequest
1 голос
/ 28 марта 2012

У меня есть массив, который взят из изображения, используя

exif_read_data($image, 0, true)

Сам массив может содержать неизвестное количество ключей / значений (также может быть 0) Массив также многомерен в некоторых частях.

Пример массива из exif_read_data:

Array
(
    [FILE] => Array
        (
            [FileName] => f-20110129_004_pp.jpg
            [FileDateTime] => 0
            [FileSize] => 3566966
            [FileType] => 2
            [MimeType] => image/jpeg
            [SectionsFound] => ANY_TAG, IFD0, THUMBNAIL, EXIF, GPS
        )

    [COMPUTED] => Array
        (
            [html] => width="2576" height="1936"
            [Height] => 1936
            [Width] => 2576
            [IsColor] => 1
            [ByteOrderMotorola] => 0
            [ApertureFNumber] => f/2.8
            [Thumbnail.FileType] => 2
            [Thumbnail.MimeType] => image/jpeg
        )

    [IFD0] => Array
        (
            [ImageWidth] => 2576
            [ImageLength] => 1936
            [BitsPerSample] => Array
                (
                    [0] => 8
                    [1] => 8
                    [2] => 8
                )

            [Make] => Nokia
            [Model] => N900
            [Orientation] => 1
            [SamplesPerPixel] => 3
            [XResolution] => 3000000/10000
            [YResolution] => 3000000/10000
            [ResolutionUnit] => 2
            [Software] => Adobe Photoshop CS5 Windows
            [DateTime] => 2011:01:29 09:37:30
            [YCbCrPositioning] => 1
            [Exif_IFD_Pointer] => 276
            [GPS_IFD_Pointer] => 658
        )

    [THUMBNAIL] => Array
        (
            [Compression] => 6
            [XResolution] => 72/1
            [YResolution] => 72/1
            [ResolutionUnit] => 2
            [JPEGInterchangeFormat] => 978
            [JPEGInterchangeFormatLength] => 5525
        )

    [EXIF] => Array
        (
            [ExposureTime] => 1/500
            [FNumber] => 14/5
            [ExposureProgram] => 0
            [ISOSpeedRatings] => 100
            [ExifVersion] => 0210
            [DateTimeOriginal] => 2011:01:29 09:37:30
            [DateTimeDigitized] => 2011:01:29 09:37:30
            [ShutterSpeedValue] => 8/1
            [ApertureValue] => 297/100
            [LightSource] => 0
            [Flash] => 0
            [FocalLength] => 26/5
            [FlashPixVersion] => 0100
            [ColorSpace] => 1
            [ExifImageWidth] => 2576
            [ExifImageLength] => 1936
            [CustomRendered] => 0
            [ExposureMode] => 0
            [WhiteBalance] => 0
            [DigitalZoomRatio] => 1/1
            [SceneCaptureType] => 0
            [GainControl] => 0
            [Contrast] => 0
            [Saturation] => 0
        )

    [GPS] => Array
        (
            [GPSVersion] => 
            [GPSLatitudeRef] => N
            [GPSLatitude] => Array
                (
                    [0] => 22/1
                    [1] => 12937/1000
                    [2] => 0/1
                )

            [GPSLongitudeRef] => E
            [GPSLongitude] => Array
                (
                    [0] => 113/1
                    [1] => 32886/1000
                    [2] => 0/1
                )

            [GPSAltitudeRef] => 
            [GPSAltitude] => 255/1
            [GPSTimeStamp] => Array
                (
                    [0] => 9/1
                    [1] => 37/1
                    [2] => 30/1
                )

            [GPSMapDatum] => WGS-84
            [GPSDateStamp] => 2011:01:29
        )

)

У меня вопрос, как я могу создать функцию, которая будет отображать только выбранные мной клавиши в виде пары ключ / значение, даже если она находится во 2-м или 3-м измерении массива?

например - из приведенного выше массива, если я хочу выбрать только [ImageWidth] , [ImageLength] , [XResolution] , [GPSTimeStamp] and [GPSLatitude] ..

Я бы передал это функции как:

$keys_array = (ImageWidth , ImageLength, XResolution, GPSTimeStamp , GPSLatitude) 

, а затем

function select_keys_from_array ($keys_array='') {  
// if $keys_array=='' then get all ..
//identify the dimension or flatten - and get only my keys and display key/value 
}

Я выбрал эти клавиши в качестве примера, потому что некоторые из них находятся на втором уровне, а некоторые на самом деле сами являются массивами ..

Существует также проблема в том, что теоретически ключи могут дублироваться (пользовательские ключи), но они находятся в другом массиве второго уровня (и поэтому номинально не дублируются).

Полагаю, мне нужно будет сначала "сплющить" его, а затем каким-то образом "передать" массив моих разыскиваемых ключей - но я не могу понять, что это правильно.

Кто-нибудь знает какой-нибудь готовый класс / функцию / фрагмент для такого рода вещей?

Ответы [ 4 ]

1 голос
/ 28 марта 2012
<?

$x = Array
(
    'FILE' => Array
        (
            'FileName' => 'f-20110129_004_pp.jpg',
            'FileDateTime' => 0,
            'FileSize' => 3566966,
            'FileType' => 2,
            'MimeType' => 'image/jpeg',
            'SectionsFound' => 'ANY_TAG, IFD0, THUMBNAIL, EXIF, GPS',
        ),

    'COMPUTED' => Array
        (
            'html' => 'width="2576" height="1936"',
            'Height' => 1936,
            'Width' => 2576,
            'IsColor' => 1,
            'ByteOrderMotorola' => 0,
            'ApertureFNumber' => 'f/2.8',
            'Thumbnail.FileType' => 2,
            'Thumbnail.MimeType' => 'image/jpeg',
        ),

    'IFD0' => Array
        (
            'ImageWidth' => 2576,
            'ImageLength' => 1936,
            'BitsPerSample' => Array
                (
                    '0' => 8,
                    '1' => 8,
                    '2' => 8,
                ),

            'Make' => 'Nokia',
            'Model' => 'N900',
            'Orientation' => 1,
            'SamplesPerPixel' => 3,
            'XResolution' => '3000000/10000',
            'YResolution' => '3000000/10000',
            'ResolutionUnit' => 2,
            'Software' => 'Adobe Photoshop CS5 Windows',
            'DateTime' => '2011:01:29 09:37:30',
            'YCbCrPositioning' => 1,
            'Exif_IFD_Pointer' => 276,
            'GPS_IFD_Pointer' => 658,
        ),

    'THUMBNAIL' => Array
        (
            'Compression' => 6,
            'XResolution' => '72/1',
            'YResolution' => '72/1',
            'ResolutionUnit' => 2,
            'JPEGInterchangeFormat' => 978,
            'JPEGInterchangeFormatLength' => 5525,
        ),

    'EXIF' => Array
        (
            'ExposureTime' => '1/500',
            'FNumber' => '14/5',
            'ExposureProgram' => 0,
            'ISOSpeedRatings' => 100,
            'ExifVersion' => '0210',
            'DateTimeOriginal' => '2011:01:29 09:37:30',
            'DateTimeDigitized' => '2011:01:29 09:37:30',
            'ShutterSpeedValue' => '8/1',
            'ApertureValue' => '297/100',
            'LightSource' => 0,
            'Flash' => 0,
            'FocalLength' => '26/5',
            'FlashPixVersion' => '0100',
            'ColorSpace' => 1,
            'ExifImageWidth' => 2576,
            'ExifImageLength' => 1936,
            'CustomRendered' => 0,
            'ExposureMode' => 0,
            'WhiteBalance' => 0,
            'DigitalZoomRatio' => '1/1',
            'SceneCaptureType' => 0,
            'GainControl' => 0,
            'Contrast' => 0,
            'Saturation' => 0,
        ),

    'GPS' => Array
        (
            'GPSVersion' => '',
            'GPSLatitudeRef' => 'N',
            'GPSLatitude' => Array
                (
                    '0' => '22/1',
                    '1' => '12937/1000',
                    '2' => '0/1',
                ),

            'GPSLongitudeRef' => 'E',
            'GPSLongitude' => Array
                (
                    '0' => '113/1',
                    '1' => '32886/1000',
                    '2' => '0/1',
                ),

            'GPSAltitudeRef' => '',
            'GPSAltitude' => '255/1',
            'GPSTimeStamp' => Array
                (
                    '0' => '9/1',
                    '1' => '37/1',
                    '2' => '30/1',
                ),

            'GPSMapDatum' => 'WGS-84',
            'GPSDateStamp' => '2011:01:29',
        ),

);

function get_values( $data, $keys ) {
    $ret = Array();
    foreach( $data as $k => $v ) {
        if( is_array( $v ) ) {
            $t = get_values( $v, $keys );
            if( is_array( $t ) && sizeOf( $t ) > 0 ) {
                $ret[$k] = $t;
            }
        } else {
            if( in_array( $k, $keys ) ) {
                $ret[ $k ] = $v;
            }
        }
    }
    return $ret;
}

print_r( get_values( $x, Array( 'ImageWidth', 'ImageLength', 'XResolution', 'GPSLatitude' ) ) );

?>

1 голос
/ 28 марта 2012

Вам не обязательно сглаживать это - на самом деле, это может перезаписать те ключи, которые вы упомянули, которые могут появиться в более чем одном подмассиве. Вам просто нужно иметь возможность успешно обходить массив, включая вложенные массивы, используя рекурсию (подпрограмма будет считывать один массив от начала до конца, но будет вызывать себя рекурсивно для каждого подмассива, с которым она сталкивается). Как только вы сможете это сделать, вы можете просто сравнить ключи, с которыми вы сталкиваетесь, с теми, которые вы хотите.

Если вы хотите, чтобы определенные версии ключей появлялись в нескольких местах, вам придется как-то их квалифицировать («охватывать») - например, используя COMPUTED.Height, а не просто Height. Ваш алгоритм обхода должен будет отслеживать путь через массив (то есть цепочку родительских массивов, по которой он прошел, чтобы пройти это расстояние), чтобы позволить это сравнение.

1 голос
/ 28 марта 2012

( Отказ от ответственности ; может делать дурацкие вещи, не полностью протестированные - должно быть в порядке)

Последнее редактирование ; первый был лучше, так как он не исключал значения массива (, такие как координаты и т. д. )

function array_by_keys_recursive(array $keys, array $array) {
    $results = array();
    foreach ($keys as $key) {
        if (isset($array[$key])) {
            $results[$key] = $array[$key];
            continue;
        }
        foreach ($array as $value) {
            if (\is_array($value)) {
                $results = \array_replace($results,
                    \array_by_keys_recursive(array($search), $value));
            }
        }
    }
    return $results;
}

Тест:

$array = array(
    'a' => 1,
    'b' => 2,
    'c' => array(
        'd' => 3,
        'e' => 4,
    ),
    'f' => 5,
    'g' => array(
        'h' => array(
            'i' => 6,
            'j' => 7,
        ),
        'k' => 8,
    ),
);

\var_dump(\array_by_keys_recursive(array('a', 'b', 'c', 'h', 'i', 'j'), $array));

Результаты:

array(6) {
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
  ["c"]=>
  array(2) {
    ["d"]=>
    int(3)
    ["e"]=>
    int(4)
  }
  ["h"]=>
  array(2) {
    ["i"]=>
    int(6)
    ["j"]=>
    int(7)
  }
  ["i"]=>
  int(6)
  ["j"]=>
  int(7)
}
1 голос
/ 28 марта 2012

Напишите рекурсивную функцию, которая преобразует многомерный массив в плоский и удаляет дубликаты ключей или те, которые вам не нужны.

function multi2flat($array) 
{
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}
...