Devolver solo entradas duplicadas de una matriz (sin distinción entre mayúsculas y minúsculas)

5 minutos de lectura

avatar de usuario de codex
codex

Quiero recuperar todas las entradas duplicadas que no distinguen entre mayúsculas y minúsculas de una matriz. ¿Es esto posible en PHP?

array(
    1 => '1233',
    2 => '12334',
    3 => 'Hello',
    4 => 'hello',
    5 => 'U'
);

Matriz de salida deseada:

array(
    1 => 'Hello',
    2 => 'hello'
);

  • Hay una pregunta similar aquí: stackoverflow.com/questions/1212605/…

    – Hasta Teis

    11 de agosto de 2009 a las 10:26

function get_duplicates ($array) {
    return array_unique( array_diff_assoc( $array, array_unique( $array ) ) );
}

  • Es el primero array_unique realmente necesario? Sin ello parece dar el mismo resultado.

    – luukvhoudt

    8 de julio a las 15:06

  • Yo creo sin el primero array_unique, si la matriz original tuviera un valor tres veces, esto devolvería una matriz que lo tenía dos veces; o si el original lo tuvo cuatro veces, la vuelta lo tendría tres veces, etc.

    – Trombón 75

    1 oct a las 22:08

  • Los comentarios anteriores explican por qué siempre es importante explicar el código en las respuestas.

    – mickmackusa

    Hace 6 horas

Avatar de usuario de Shiva Srikanth Thummidi
Shiva Srikanth Thummidi

<?php
function array_not_unique($raw_array) {
    $dupes = array();
    natcasesort($raw_array);
    reset($raw_array);

    $old_key   = NULL;
    $old_value = NULL;
    foreach ($raw_array as $key => $value) {
        if ($value === NULL) { continue; }
        if (strcasecmp($old_value, $value) === 0) {
            $dupes[$old_key] = $old_value;
            $dupes[$key]     = $value;
        }
        $old_value = $value;
        $old_key   = $key;
    }
    return $dupes;
}

$raw_array    = array();
$raw_array[1] = 'abc@xyz.com';
$raw_array[2] = 'def@xyz.com';
$raw_array[3] = 'ghi@xyz.com';
$raw_array[4] = 'abc@xyz.com'; // Duplicate

$common_stuff = array_not_unique($raw_array);
var_dump($common_stuff);

  • Buena solución para matriz bidimensional también, si usamos array_map("serialize", $arr); antes de. ¡Gracias!

    – Tipo_booleano

    5 de mayo de 2016 a las 13:24

avatar de usuario de ryanday
ryanday

Deberá hacer que su función no distinga entre mayúsculas y minúsculas para obtener el resultado “Hola” => “hola” que está buscando, pruebe este método:

$arr = array(1=>'1233',2=>'12334',3 =>'Hello' ,4=>'hello', 5=>'U');

// Convert every value to uppercase, and remove duplicate values
$withoutDuplicates = array_unique(array_map("strtoupper", $arr));

// The difference in the original array, and the $withoutDuplicates array
// will be the duplicate values
$duplicates = array_diff($arr, $withoutDuplicates);
print_r($duplicates);

La salida es:

Array
(
[3] => Hello
[4] => hello
)

Editado por @AlixAxel:

Esta respuesta es muy engañosa. Solo funciona en esta condición específica. Este contraejemplo:

$arr = array(1=>'1233',2=>'12334',3 =>'Hello' ,4=>'HELLO', 5=>'U');

falla miserablemente. Además, esta no es la forma de mantener duplicados:

array_diff($arr, array_unique($arr));

Dado que uno de los valores duplicados estará en array_uniquey luego cortado por array_diff.

Editado por @RyanDay:

Así que mire la respuesta de @ Srikanth o @ Bucabay, que funcionan para todos los casos (busque mayúsculas y minúsculas en Bucabay), no solo los datos de prueba especificados en la pregunta.

  • Una manera muy limpia y agradable de hacerlo. Agregue algunos comentarios para que los codificadores de PHP novatos puedan entender: es posible escribir un código limpio con ese lenguaje, y debe saberse 🙂

    – e-satis

    11 de agosto de 2009 a las 10:44

  • Por cierto, si la matriz es muy larga, recomiendo tener un ejemplo usando el patrón iterador del SPL para ahorrar memoria.

    – e-satis

    11 de agosto de 2009 a las 10:45

  • @rday: observe que su sujeto de prueba contiene números y una “U” mayúscula que son todas mayúsculas en lo que respecta a strtoupper(). Los resultados devueltos son los valores de mayúsculas y minúsculas que modificó strtoupper(), no los duplicados. Si el cartel necesita ambos duplicados, entonces la solución que John propuso hará el trabajo de manera bastante eficiente con una complejidad de tiempo de O (n), que creo que es el mejor caso aquí.

    – bucabay

    11 de agosto de 2009 a las 21:48

  • -1, esto es un error total: codepad.org/7NQ9lQLU. Funciona solo por pura casualidad.

    – Alix Axel

    20/10/2012 a las 16:55


  • desperdicié mis 15 minutos shud he visto el comentario de @AkshatSinghal

    – mokNathal

    6 oct 2015 a las 11:18

Avatar de usuario de Alix Axel
Alix Axel

Esta es la forma correcta de hacerlo (distingue entre mayúsculas y minúsculas):

array_intersect($arr, array_unique(array_diff_key($arr, array_unique($arr))));

Y una solución que no distingue entre mayúsculas y minúsculas:

$iArr = array_map('strtolower', $arr);
$iArr = array_intersect($iArr, array_unique(array_diff_key($iArr, array_unique($iArr))));

array_intersect_key($arr, $iArr);

Pero la respuesta de @Srikanth es más eficiente (en realidad, es la única que funciona correctamente además de este).

avatar de usuario de bucabay
bucabay

function array_not_unique($raw_array) {
    $dupes = array();
    natcasesort($raw_array);
    reset($raw_array);

    $old_key   = NULL;
    $old_value = NULL;
    foreach ($raw_array as $key => $value) {
        if ($value === NULL) { continue; }
        if (strcasecmp($old_value, $value) === 0) {
            $dupes[$old_key] = $old_value;
            $dupes[$key]     = $value;
        }
        $old_value = $value;
        $old_key   = $key;
    } return $dupes;
}

Lo que Srikanth (john) agregó pero con la comparación sin distinción entre mayúsculas y minúsculas.

Probar:

$arr2 = array_diff_key($arr, array_unique($arr));

mayúsculas y minúsculas:

array_diff_key($arr, array_unique(array_map('strtolower', $arr)));

Avatar de usuario de Bossman
Jefe

La publicación de 12 años y la respuesta aceptada devuelve una matriz en blanco y otras son largas.

Aquí está mi opinión para los futuros Googlers que es breve y devuelve TODOS los índices duplicados (¿índices?).

$myArray = array('fantastic', 'brilliant', 'happy', 'fantastic', 'Happy', 'wow', 'battlefield2042 :(');

function findAllDuplicates(array $array)
{
    // Remove this line if you do not need case sensitive.
    $array = array_map('strtolower', $array);

    // Remove ALL duplicates
    $removedDuplicates = array_diff($array, array_diff_assoc($array, array_unique($array)));

    return array_keys(array_diff($array, $removedDuplicates));
    // Output all keys with duplicates
    // array(4) {
    //   [0]=>int(0)
    //   [1]=>int(2)
    //   [2]=>int(3)
    //   [3]=>int(4)
    // }


    return array_diff($array, $removedDuplicates);
    // Output all duplicates
    // array(4) {
    //   [0]=>string(9) "fantastic"
    //   [2]=>string(5) "happy"
    //   [3]=>string(9) "fantastic"
    //   [4]=>string(5) "happy"
    // }
}

¿Ha sido útil esta solución?