PDA

View Full Version : شیفت دادن یک آرایه از شماره ردیفها وقتی یک عدد بین این ردیفها باید اضافه شود



H:Shojaei
دوشنبه 28 اردیبهشت 1394, 13:06 عصر
سلام...
فرض کنید 100 تا المنت توی صفحه داریم... که این المنتها مثلا تگ <p> هستن و هرکدوم یه مشخصه منحصر به فرد دارن که از دیتابیس گرفته میشه واسشون اون مشخصه هم sid هست...
مثل:
<p sid=1>
<p sid=2>
<p sid=3>
این اعداد sid ها از دیتابیس گرفته میشن و هر تغییراتی داده بشه باید تو دیتابیس هم اعمال بشه...
تعداد این <p>ها ممکنه هر چندتایی ولی احتمالا زیر 300-400 تا باشه حالا فرض کنید بین این تگهای با sid شماره 2 و 3 قراره یک تک دیگه اضافه بشه و این باید داخل دیتابیس طوری درج بشه که من دفه بعد که خواستم بخونم بدونم که اینی که اضافه شده به دیتابیس باید بعد شماره 2 بیاد...
حالا سوالم اینه که واسه این کار شماره تگها رو شیفت بدم؟ یا روش بهینه ای هم وجود داره که این کارو بکنم؟
الآن که مینوشتم یه راه به ذهنم رسید این که هرکدوم رو یه ند در نظر بگیرم و شماره sid بعدی و قبلیش رو هم تو دیتابیس ذخیره کنم مثلا 2 قبلیش میشه 1 و بعدیش میشه 3 ولی باز اگر بخوام یکی بین 2 و 3 درج کنم شماره اون رو چی بذارم مثلا بذارم 4 بعد 4 قبلش 2 میشه و بعدش 3 و 2 بعدیش میشه 4 که جدیده و 3 هم که قبلیش عوض شده میشه 4 حالا وقتی میخوام از دیتابیس بخونم چطور این ترتیب رو رعایت کنم؟ یا وقتی گرفتم از دیتابیس چطور به بهترین روش اینها رو به ترتیب نشون بدم؟!
بازم دوستان نظر دبگه ای داشتین بگین ممنون میشم که به بهترین راه انجام بشه این کار تشکر...

abolfazl-z
دوشنبه 28 اردیبهشت 1394, 13:44 عصر
از یک فیلدی به نام position استفاده کنید و بجای اینکه sid را شیفت بدهید positioon را شیفت بدهید.

abolfazl-z
دوشنبه 28 اردیبهشت 1394, 13:48 عصر
مثلا سه المنت داری :

element => position
a => 1
b => 2
c => 3

یک المنت جدیدی به نام d می خواهیم در بین a و b اضافه کنیم. یعنی موقعیت 2

پس هر سطری که position > 2 هست را یکی اضافه می کنیم.

a => 1
d => 2
b => 3
c => 4

H:Shojaei
دوشنبه 28 اردیبهشت 1394, 18:12 عصر
ممنون ولی این اولین راه حلیه که به ذهنم رسید و به جای این position هم از اون نود که گفتم خودم استفاده بشه بهتر و بهینه تر هست چون فرض کنید 1000 رکورد داریم بعد بین اولی و دومی یکی اضافه میشه در این حالت باید 999 تاشون ویرایش بشن که این خوب نیست...
راستی راهشم پیدا کردم میگم: در حقیقت به لیست پیوندی یک طرفه به راحتی قابل انجامه اون بالا هم گفتم اسمش یادم نمیومد الگوریتمشو با این کار کلا یک دو تا رکورد همیشه ویرایش میشه...
به این صورت که یه next-nod داریم واسه هر المنت و یه sid وقتی وسط دوتا المنت یکی دیگه بخواد درح بشه میایم به جدیده یه sid میدیم next-nod المنت قبلیش رو میذاریم تو next-nod المنت جدیدمون و برابر باز next-nod المنت قبلی رو برابر با sid المنت جدید میذاریم اینطوری هر کدوم به بعدی اشاره میکنه و هر جایی هم میشه یه المنت جدید به همین شیوه درج کرد...
(بلاخره تحصیلات آکادمیک یه جایی به درد خورد ;) )

abolfazl-z
دوشنبه 28 اردیبهشت 1394, 22:55 عصر
:لبخندساده:

چقدر سریع فضاوت می کنید !

لیست پیوندی کجا و راه حل شما کجا !

شاید کار شما را راحت کند ولی شما می خواهین داده ها را بصورت سطری از آرایه بخوانید و یک لیست پیوندی درست کنید !!!!!! آیا update شما بیشتر است یا select؟

طبیعتا select از آپدیت بیشتره !

ولی یکم فکر کردم تا به الگوریتم جالبی رسیدم. درواقع تکمیل شده راه حل قبلی که گفتم است

شما نوع فیلد position را اعشاری(double) در نظر بگیرید.

بعد زمانی که می خواهید بین دو item یک item جدید اضافه کنید یک عدد اعشاری بین عدد بالا و پایین پیدا کنید و داده جدید را با آن position ذخیره کنید.

بهینه سازی خیلی بالایی داره و خیلی جالب است که من الان از این به بعد خودم می خواهم از این الگوریتم استفاده کنم.

از آنجایی که اعداد اعشاری بین دو عدد خیلی زیاد است شما می توانید از این روش استفاده کنید.

بعد از یک مدت هم همه داده ها را بخوانید و از یک تا n مرتب سازی کنید تا به مشکل خاصی بر نخورید !

اینطوری شما نه دیگه آپدیت دارین و نه ساختن لیست پیوندی و ... از خود مرتب سازی mysql استفاده می کنید.

حالا اجرایی اش کنید ببینیم چی میشه...

H:Shojaei
سه شنبه 29 اردیبهشت 1394, 00:57 صبح
ممنون بازم راه حل خوبی دادین این که select از update بیشتر دارم منظورتون رو نفهمیدم...
در حقیقت من یه بار سلکت میکنم و بعد از اون فقط باید لیست رو پیمایش کنم... که در کل به لحاظ مرتبه اجرا از همین اعشار چیزی اضافه نداره...
این که میگید لیست پیوندی کجا و این کجا خوب لیست پیوندی واسه همینطور مواقع هست که دیگه همچین دور هم که میگین نیست...
عدد اعشاری هم خوبه ولی باید ببینم چطور میشه مشکلی چیزی نداشته باشه...
ولی فکر میکنم اعشار هم دردسرای زیادی داره فرض کنید این دوتارو داریم:
1.256 و 2.587
حالا بینشون یکی میخوایم اضافه کنیم... فرضا میشه 1.256 , 1.257 , 2.587 خوب درسته...
حالا میخوام یک عدد دیگه بین دوتای اولی درج کنم چی میشه؟؟! 1.256 , 1.2561 , 1.257 , 2.587 یعنی یک عدد اعشار هر بار که بخوایم اینطوری عمل کنیم نیازه...
حالا تا چند تا اعشار باید توی دیتابیس تعیین کنیم؟! الآن من لیست پیوندی رو پیاده کردم جواب هم گرفتم فقط هنوز پیمایشش نکردم ببینم چطور میشه...

MMSHFE
سه شنبه 29 اردیبهشت 1394, 09:52 صبح
اینکه از چه الگوریتمی استفاده کنید بستگی به نیاز شما در مسئله داره ولی اون چیزی که براساس عنوان تاپیکتون میتونم بگم اینه که اگه بخواین یه چیزی وسط آرایه توی خونه مشخصی اضافه کنید، میتونید چنین کدی بنویسید:

function insertInArray(&$array, $value, $position) {
$result = array();
$inserted = false;
$increment = 0;
foreach ($array as $k => $v) {
if (!$inserted && $k >= $position) {
$result[$k] = $value;
$increment++;
$inserted = true;
}
$result[$k + $increment] = $v;
}
$array = $result;
/*
if($position >= count($array)) {
return;
}
$firstPart = array_slice($array, 0, $position);
$secondPart = array_slice($array, $position);
$array = array_merge($firstPart, array($value), $secondPart);
*/
}
$numbers = array(5, 7, 9, 2, 1, 6);
insertInArray($numbers, 4, 3);
echo '<pre>' . print_r($numbers, true) . '</pre>';
هر دو نمونه کد داخل تابع کار میکنن (کدی که گذاشته شده و کد کامنت شده). نمونه خروجی:

Array
(
[0] => 5
[1] => 7
[2] => 9
[3] => 4
[4] => 2
[5] => 1
[6] => 6
)

H:Shojaei
سه شنبه 29 اردیبهشت 1394, 11:21 صبح
ممنون جناب شهرکی کدی که دادین واسه عنوان تاپیک که زدم خوبه ولی اون دیگه مد نظرم نیست اگر بخوام این کارو بکنم هربار که کاربری بخواد یک عدد بین اینها اضافه کنه که هر لحظه ممکنه این کارو بکنه باید تمام رکوردهای بعد از اون جایی که اضافه کرده رو تو دیتابیس ویرایش کنم...
به نظر خودم که همون لیست پیوندی از همه بهتر باشه هم کم باره هم ساده تنها چیزی که نیازه تغییر کنه نهایت تو هر بار دوتا رکورد میشه و هیچ مشکلی هم به جز هنگام نمایش دادن که نهایت نهایت دوتا حلقه تو در تو میشه (که اونم باز احتمالا راه حل داره که تو در تو نشه شاید) و عدد بعدی از این عددی که هستیم پیدا بشه...

abolfazl-z
سه شنبه 29 اردیبهشت 1394, 18:13 عصر
این کد خلاصه شده جناب آقای شهرکی :


$numbers = array(5, 7, 9, 2, 1, 6);
$pos = 3;
$val = 4;
array_splice($numbers,$val-1,0,$val);
print_r($numbers);


ممنون بازم راه حل خوبی دادین این که select از update بیشتر دارم منظورتون رو نفهمیدم...

یعنی اینکه تعداد select هایی که در روز میزنین از تعداد update ها بیشتر است. این نتیجه را میتونین بروید از phpmyadmin ببینید و مشاهده کنید که چقدر update و select دارین.


ولی فکر میکنم اعشار هم دردسرای زیادی داره فرض کنید این دوتارو داریم:
1.256 و 2.587
حالا بینشون یکی میخوایم اضافه کنیم... فرضا میشه 1.256 , 1.257 , 2.587 خوب درسته...
حالا میخوام یک عدد دیگه بین دوتای اولی درج کنم چی میشه؟؟! 1.256 , 1.2561 , 1.257 , 2.587 یعنی یک عدد اعشار هر بار که بخوایم اینطوری عمل کنیم نیازه...

شما فقط باید یک الگوریتمی پیدا کنید که بین دو عدد نزدیک ترین عدد مابین را بدهد.


حالا تا چند تا اعشار باید توی دیتابیس تعیین کنیم؟! الآن من لیست پیوندی رو پیاده کردم جواب هم گرفتم فقط هنوز پیمایشش نکردم ببینم چطور میشه...

همین پیمایش میدونین چقدر داستان داره ! چقدر for و شرط و ... !!!

این راه حلی که من دادم از هر لحاظی بهنیه است. حالا خودتون میدانید اگر داده هایتان زیاد نیست یعنی زیر چند هزار تا است همه این الگوریتم هایی که اینجا گفته شده جواب میده و لزوما به این معنی نیست که جواب نده ولی بر روی داده های کم.

MMSHFE
سه شنبه 29 اردیبهشت 1394, 23:10 عصر
ممنون از تکه کد کوتاه شده که گذاشتین. البته من منظورم استفاده از array_slice بود که اشتباهاً از splice استفاده کرده بودم که الان اصلاحش کردم. البته همونطور که اشاره کردین، با کمک splice کد کوتاهتر میشه. ضمناً اگه به استارتر کمک میکنه، با کمک دستور زیر میتونید توی دیتابیس، تمام id ها رو از 1 به بعد به ترتیب شماره بزنید:
SET @var:=0;
UPDATE `table` SET `id`=(@var:=@var+1);
که اگه توی قیدهای مربوط به Relationها در قسمت ON UPDATE گزینه CASCADE رو انتخاب کرده باشین، کلیدهای خارجی در جدولهای وابسته هم خودبخود اصلاح میشن.