Обход 2-мер. массива

bzik

Новичок
Обход 2-мер. массива

Не могу преобразовать 2-мер. массив.
Например имеется:
Array
(
[6] => Array
(
[1] => aaa
[3] => ccc
)

[8] => Array
(
[1] => bbb
[3] => ccc
[5] => ccc
)
)

Надо удалить одинаковые элементы, встречающиеся сразу во всех подмассивах. Т.е. должно получиться:
Array
(
[696] => Array
(
[1] => aaa
)

[698] => Array
(
[1] => bbb
[5] => ccc
)
)

Поможите, люди добрые, а то совсем голову сломал.
 

Stm

Новичок
function f($a){
$i=sizeof($a);
while($i--){
$j=sizeof($a);
$u=array();
while($j--) if($i!=$j) $u=array_merge($u,array_diff($a[$i],$a[$j]));
$a[$i]=array_unique($u);
}
return $a;
}
 

.des.

Поставил пиво кому надо ;-)
2 Stm вы внимательно прочитали вопрос?
Надо удалить одинаковые элементы, встречающиеся сразу во всех подмассивах.
Решение возможно следующее
PHP:
array_walk($a, create_function('&$v,$k,&$da', '
  foreach($v as $i=>$t) { 
    if(isset($da[$t])) unset($v[$i]); 
    $da[$t]=1;
 }'), $da);
Вот тестовый массив
PHP:
$a = array
(
	'6' => array
	(
		'1' => 'aaa',
		'3' => 'ccc'
	),
	'8' => array
	(
		'1' => 'bbb',
		'3' => 'ccc',
		'5' => 'ccc'
	),
	'2' => array
	(
		'1' => 'aaa',
		'3' => 'ccc'
	)
);
 

Vasya

Guest
PHP:
// version 1.0
// function removes row[s] with identical values in all cols
function remove_dups(&$a) {
	$b = array_keys($a);
	$i0 = $b[0];
	$b1 = $b;
	array_shift($b1);
	$c = $a[$i0];
	for(reset($c); list($k,$v) = each($c); ) {
		$delete = true;
		for(reset($b1); list($kb,$vb) = each($b1); ) {
			if($a[$vb][$k] !== $v) {
				$delete = false;
				break;
			}
		}
		for(reset($b); (list($k1,$v1) = each($b)) && $delete; ) {
			unset($a[$v1][$k]);
		}
	}
}
 

.des.

Поставил пиво кому надо ;-)
2 Vasya :) вы уверены что она делает, то что хотел автор?

например, тестовый массив она обработала так
PHP:
Array
(
    [6] => Array
        (
            [1] => aaa
        )

    [8] => Array
        (
            [1] => bbb
            [5] => ccc
        )

    [2] => Array
        (
            [1] => aaa
        )

)
последняя aaa лишняя.

да и стоит задуматься об эффективности. ну и читаемости :)
 

Vasya

Guest
вы уверены что она делает, то что хотел автор?
Она делает то, что хотел я. После того как прочитал условие задачи и, исходя из того, что я понял в том, что прочитал.
последняя aaa лишняя.
Надо удалить одинаковые элементы, встречающиеся сразу во всех подмассивах.
да и стоит задуматься об эффективности. ну и читаемости
Конечно! :)
- надо проверять входной параметр и его первый эелемент на is_object()
- надо вообще сделать покрасивше код
- ...
Но для первой работающей версии она меня устраивает...
Кстати, с удовольствием посмотрю на более красивое решение!
 

.des.

Поставил пиво кому надо ;-)
Кстати, с удовольствием посмотрю на более красивое решение!
PHP:
array_walk($a, create_function('&$v,$k,&$da', ' 
  foreach($v as $i=>$t) { 
    if(isset($da[$t])) unset($v[$i]); 
    $da[$t]=1; 
}'), $da);
Смотрите внимательнее я приводил его выше.

Надо удалить одинаковые элементы, встречающиеся сразу во всех подмассивах.
и почему ааа не было удалено? :))
для первой работающей версии она меня устраивает
в том то и дело, что код не рабочий!
 

Vasya

Guest
Автор оригинала: .des.
PHP:
array_walk($a, create_function('&$v,$k,&$da', ' 
  foreach($v as $i=>$t) { 
    if(isset($da[$t])) unset($v[$i]); 
    $da[$t]=1; 
}'), $da);
Смотрите внимательнее я приводил его выше.
Этот код не удаляет
$a[6][3] => 'ccc'

и почему ааа не было удалено? :))
Потому что его нет во втором массиве.

в том то и дело, что код не рабочий!
Мы с вами по-разному понимаем условия задачи. Поэтому договориться не можем. Пусть разбирается автор темы. Ок?
 

.des.

Поставил пиво кому надо ;-)
2 Vasya.

Вы, действительно, предположительно правильнее поняли задачу.
"сразу во всех подмасивах" = "то есть, те которые есть в КАЖДОМ"

тогда задача усложняется :)
Тем не менее приведу альтернативное решение.
Алгоритм у обоих следующий: подсчет количества одинаковых значений и последующее удаление тех чья


PHP:
// ======================================
// Вариант 1.
// $a - исходный массив.
// Подсчитываем количество одинаковых элементов в массиве.
// Важно обратить внимание на строку
// $v = array_unique($v);
// Это исключает возможность удаления таких элементов , 
// значения которых  повторяются в пределах одного 
// подмассива.

$cn = array_reduce($a, create_function('$p,$v','
	$v = array_unique($v);
	foreach($v as $i=>$t) 
		$p[] = $t;
	return $p;
	'));
$cn = array_count_values($cn);

$c = sizeof($a);
array_walk($a, 
	create_function('&$v,$k,$p', '
	$cn = $p[0]; $c = $p[1];
	foreach($v as $i=>$t) 
		if($cn[$t]>=$c) unset($v[$i]); 
	'), array(&$cn,$c) );

PHP:
// ======================================
// Вариант 2.
// Алгоритм тот же.

$c = sizeof($a);
array_walk($a, 
	create_function('&$v,$k,&$cn', '
	$v = array_unique($v);
	foreach($un as $i=>$t) 
		$cn[$t] = isset($cn[$t])? $cn[$t]+ 1 : 1;
	'), &$cn);
array_walk($a, 
	create_function('&$v,$k,$p', '
	$cn = $p[0]; $c = $p[1];
	foreach($v as $i=>$t) 
		if($cn[$t]>=$c) unset($v[$i]); 
	'), array(&$cn,$c) );
в том то и дело, что код не рабочий!
Мы с вами по-разному понимаем условия задачи. Поэтому договориться не можем. Пусть разбирается автор темы. Ок?
Продолжаю настаивать! Код не совсем рабочий :)
PHP:
// Исходный массив
$a = array
(
	'6' => array
	(
		'1' => 'aaa',
		'3' => 'ccc'
	),
	'8' => array
	(
		'1' => 'bbb',
		'3' => 'ccc',
		'5' => 'ccc',
		'6' => 'aaa'
	),
	'2' => array
	(
		'1' => 'aaa'
	)
);
//==========================
// Результат обработки функцией remove_dups

Notice: Undefined offset: 3 in w:\home\tst\www\tst.php on line 77

Array
(
    [6] => Array
        (
            [1] => aaa
            [3] => ccc
        )

    [8] => Array
        (
            [1] => bbb
            [3] => ccc
            [5] => ccc
            [6] => aaa
        )

    [2] => Array
        (
            [1] => aaa
        )

)

// aaa не удален.
 

Vasya

Guest
Продолжаю настаивать! Код не совсем рабочий
Ну, что ж... давайте продолжим... дискуссию...
Мой код совсем, совсем рабочий.
А почему он должен быть удален?
Надо удалить одинаковые элементы, встречающиеся сразу во всех подмассивах.
Я понял это так, что И индекс, И значение должны совпадать.
Этот вывод я сделал из того, что в исходном массиве имеется подмассив
Код:
[8] => Array
(
[1] => bbb
[3] => ccc
[5] => ccc
)
а на выходе у автора получается

Код:
[698] => Array
(
[1] => bbb
[5] => ccc
)
Как видно [3]=>'ccc' удален, а [5]=>'ccc' -- нет.
 

Vasya

Guest
Трактат о Лисе (Сунь Ху Вчай, 3в. до н.э.)

Из классических источников известно, что эту задачу задала мудрая госпожа Ля советнику Пу, когда они беседовали о свойсве вод течь. Мы же опустим все эти китайские церемонии.

Итак, математически задача записывается следующим образом:
Дан двумерный ассоцицативный (разреженый) массив.
Требуется удалить полные столбцы, содержащие одинаковые элементы.
Где полным считается столбец, содержащий элементы из всех строк массива.

В таком виде эта задача выглядит как типовая школьная, не так ли?

Решение:
Берем первую (любую) строку и начинаем перебирать элементы в ней.
Это "эталонные" значения для столбцов.
В столбце перебираем оставшиеся элементы, сравнивая их поочередно с выбранным из первой строки.
Если встречаем элемент не равный "эталонному", идем к следующему столбцу.
Если все элементы в столбце равны "эталонному", тогда удаляем столбец.

Из приведенного, видно, что можно оптимизировать программу если в качестве "первой" строки выбрать наикратчайшую.

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

При чем же тут Лиса? А Лиса тут совершенно ни при чем... :D
 

bzik

Новичок
Спасибо, друзья, всем откликнувшимся.
Василий, Вы совершеннно верно поняли условие задачи, ваш пример рабочий, спасибо. Сорри за непонятное/неполное изложение: элементы в границах каждого подмассива уникальны.
 

Vasya

Guest
2 bzik:
Спасибо за вопрос!
Отвечать на него было весело! :D
 
Сверху