2016-08-17 6 views
7

मेरे पास PHP में एक बहुआयामी सरणी है, जहां बाहरी सरणी में कई हजार आइटम हैं और प्रत्येक आइटम अंदर एक सरणी है जो "key1", "key2" मानों के साथ है और "गिनती":PHP बहुआयामी सरणी: दो मानों के संगतता के साथ सभी कुंजियों को प्रतिस्थापित करें

myExistingArray (size=99999 VERY BIG) 
     public 0 => 
     array (size=3) 
      'key1' => string '15504' 
      'key2' => string '20' 
      'count' => string '1' 
     public 1 => 
     array (size=3) 
      'key1' => string '15508' (length=5) 
      'key2' => string '20' (length=2) 
      'count' => string '2' (length=1) 
     public 2 => 
     array (size=3) 
      'key1' => string '15510' (length=5) 
      'key2' => string '20' (length=2) 
      'count' => string '5' (length=1) 
....many more similar items 

मैं एक बहुत ही सरल सरणी, जहां "कुंजी 1" और से पूर्व मूल्यों "कुंजी" एक नया महत्वपूर्ण यह है कि corressponding के लिए अंक होने के लिए concatenated रहे हैं "गिनती" में इस बदलना चाहते हैं मूल्य जैसे:

myNewArray (size=99999 VERY BIG) 
     <key1>_<key2> => <count> 
     15504_20 => string '1' (length=1) 
     15508_20 => string '2' (length=1) 
     15510_20 => string '5' (length=1) 

प्रदर्शन मेरे लिए बहुत महत्वपूर्ण है क्योंकि बाहरी सरणी में कई हजार वस्तुएं हैं। PHP में एक तेज विधि है? केवल एक चीज मुझे मिल गया एक सरल यात्रा थी, लेकिन यह मेरे लिए धीमा करने के लिए लगता है:

// works but I am looking for a faster version 
$myNewArray = array(); 
foreach ($myExistingArray as $item) { 
    $myNewArray [$item["key1"]."_".$item["key1"]]=$item["count"]; 
} 

संपादित करें/मूल समस्या

कुछ लोगों को हक ने कहा कि मेरे वर्तमान समाधान में हे (एन) पहले से ही है और उल्लेख किया कि इस गति को गति देने के लिए PHP में कोई अंतर्निहित फ़ंक्शन नहीं है।

मुझे एक mysql डेटाबेस क्वेरी से "myExistingArray" मिलता है। मैं मूल रूप से नौकरी की वस्तुएं रखता हूं और उन्हें अपनी स्थिति और उनके event_id द्वारा समूहित करना चाहता हूं। यह करने के लिए क्वेरी समान:

select count(job.id) as count, job.status as key1, job.event_id as key2 
from job 
group by job.status, job.event_id 

मैं इतना है कि बाद में मैं आसानी से नौकरियों की गिनती एक निश्चित घटना के लिए एक निश्चित स्थिति के साथ उपयोग कर सकते हैं कुंजी को पुनर्व्यवस्थित करना चाहते हैं।

+0

array_column –

+1

का उपयोग करने का प्रयास करें "बहुत धीमी" क्या है? आपका सुझाव ओ (एन) लगता है जो इस तरह की चीज़ के लिए जितना तेज़ हो जाता है। – Erik

+0

डेटा कहां से शुरू हो रहा है? हो सकता है कि आप बदल सकें कि डेटा कैसे संग्रहीत किया जाता है, या यह कैसे प्रदान किया जाता है, और इस तरह से डेटा को संसाधित करने से बचने से बचें। वैसे भी, यदि यह असंभव है, तो आपके पास लूप जितना आसान हो उतना आसान होता है, जो अक्सर (इस मामले सहित) का मतलब है कि यह चीजों को करने का सबसे तेज़ तरीका है। सभी डेटा को इटरेट करना और एक नई सरणी बनाना _always_ _O (n) _ ऑपरेशन होगा, क्योंकि *** प्रत्येक तत्व को संसाधित करने की आवश्यकता है *** –

उत्तर

2

आमतौर पर, आप PHP में या तो array_walk या बदलने के लिए हो सकता है array_map समारोह सरणियों के लिए विचार करना होता, लेकिन दुर्भाग्य से उनमें से कोई सरणी है कि आप बदलना चाहते हैं की कुंजी बदल सकते हैं। array_walk कुंजी को सुरक्षित रखेगा, लेकिन उन्हें बदल नहीं पाएगा। तो दुख की बात है, नहीं, आप जो भी पूछ रहे हैं उसे करने के लिए कोई काम नहीं किया गया है।

+0

की मदद करने की संभावना अधिक है, यह एक टिप्पणी होनी चाहिए। किसी भी तरह से, भले ही एक अंतर्निहित फ़ंक्शन हो, आंतरिक रूप से इसे वही करना होगा जैसा कि ओपी वैसे भी कर रहा है। यह अभी भी एक _ ओ (एन) _ ऑपरेशन होगा। और यदि आप मिश्रण में कॉलबैक फ़ंक्शन जोड़ते हैं, तो यह निश्चित रूप से एक साधारण 'foreach' –

+0

की तुलना में _slower_ होने वाला है, शायद एक टिप्पणी बेहतर होगी। मैं मानता हूं कि एक अंतर्निहित फ़ंक्शन के साथ गति में वृद्धि नहीं होगी, लेकिन मुझे लगता है कि ओपी का मतलब है कि इसमें अधिक कार्यात्मक प्रोग्रामिंग उन्मुख दृष्टिकोण की मांग की जाए, विशेष रूप से संभव स्थान सुधारने की कमी के कारण, यही कारण है कि मैं भी उन कार्यों के संदर्भ में जो सामान्य रूप से सरणी परिवर्तनों के लिए उपयोग किए जाएंगे –

0

आप चाबियाँ पर केवल पुनरावृति करने के लिए अपने foreach को बदल सकता है और नहीं पूरे उप-सरणियों, करने के लिए इसे बदलने के द्वारा:

foreach (array_keys($myExistingArray) as $item) { 
    $myNewArray[$myExistingArray[$item]['key1'] . '_' . $myExistingArray[$item]['key2']] = $myExistingArray[$item]['count']; 
} 

यह आपको कुछ मामूली गति लाभ हासिल होगा (बार here की तुलना देख (array_keys विधि) और here (आपकी मूल विधि))। बहुत बड़े सरणी पर, अंतर अधिक उल्लेखनीय हो जाएगा।

+0

सुनिश्चित नहीं है कि 'array_keys' का उपयोग करने से बड़े सरणी पर समग्र प्रदर्शन बढ़ जाएगा। 'array_keys' को कॉल करना एक नई सरणी बनाता है, जिसका अर्थ है कि अधिक मेमोरी आवंटित करना और नया ज़वल बनाना। यह संभावना है कि संदर्भ द्वारा 'foreach ($ myExistingArray as & $ arr)' का उपयोग करके पुनरावृत्ति करना अभी भी तेज़ है ... किसी भी तरह से, मुझे लगता है कि यह माइक्रो-ऑप्टिमाइज़ेशन है, जो कि XY समस्या होने की संभावना है –

1

निम्नलिखित परिणामों के साथ कुछ परीक्षण किया गया (लगभग सभी वही)।

Test 1: [0.25861501693726] 
Test 2: [0.20804476737976] 
Test 3: [0.21039199829102] 
Oldskool:[0.26545000076294] 
Test 4: [0.35072898864746] 

मर्ज किए गए सरणी पर एक var_dump() कर बातें धीमी हो जाएगी (उम्मीद के रूप में), लेकिन यदि आप इसे स्मृति रखने डेटा भी साथ काम करने के लिए बुरा नहीं है।

और पीएचपी परीक्षण के लिए इस्तेमाल किया:

// Construct the raw data 
$i = 0; 
do { 
    $raw[] = array('key1' => mt_rand(10000,99999), 'key2' => mt_rand(10,99), 'count' => $i); 
} while(++$i < 100000); 

// Test 1 
$before = microtime(true); 
foreach($raw as $k => $v) { 
    $clean[$v['key1'].'_'.$v['key2']] = $v['count']; 
} 
$after = microtime(true); 
echo 'Test 1:['.($after - $before).']<br />'; 

$clean = false; 
$i = 0; 

// Test 2 
$before = microtime(true); 
$max = count($raw); 
do { 
    $clean[$raw[$i]['key1'].'_'.$raw[$i]['key2']] = $raw[$i]['count']; 
} while(++$i < $max); 
$after = microtime(true); 
echo 'Test 2:['.($after - $before).']<br />'; 

$clean = false; 
$i = 0; 

// Test 3 
$before = microtime(true); 
$max = count($raw); 
for($i; $i < $max; $i++) { 
    $clean[$raw[$i]['key1'].'_'.$raw[$i]['key2']] = $raw[$i]['count']; 
} 
$after = microtime(true); 
echo 'Test 3:['.($after - $before).']<br />'; 

$clean = false; 

// Test of Oldskool's suggestion 
$before = microtime(true); 
foreach (array_keys($raw) as $item) { 
    $clean[$raw[$item]['key1'].'_'.$raw[$item]['key2']] = $raw[$item]['count']; 
} 
$after = microtime(true); 
echo 'Test Oldskool:['.($after - $before).']<br />'; 

$clean = false; 
$i = 0; 

// Test 4, just for fun 
$before = microtime(true); 
$max = count($raw); 
do { 
    $c = array_pop($raw[$i]); 
    $clean[join('_', $raw[$i])] = $c; 
} while(++$i < $max); 
$after = microtime(true); 
echo 'Test 4:['.($after - $before).']<br />'; 

संपादित: Oldskool उदाहरण के लिए एक परीक्षण जोड़ा गया।

0

यदि गति समस्या है, और आप मानचित्र के रूप में अंतिम सरणी का उपयोग नहीं कर रहे हैं, तो मैं जनरेटर तैयार करूंगा, ताकि आपको सबकुछ सटीक करने की आवश्यकता न हो।

$myExistingArray = [ ... ]; 
class MyNewArrayIterator implements IteratorAggregate { 
    protected $array; 
    public function __construct(array $array) { 
     $this->array = $array; 
    } 
    public function getIterator() { 
     foreach ($this->array as $value) { 
      yield $value['key1'] . '_' . $value['key2'] => $value['count']; 
     } 
    } 
} 

और फिर आप कर सकते हैं:

$myNewArray = new MyNewArrayIterator($myExistingArray); 
foreach($myNewArray as $key => $value) { 
    echo $key . ": " . $value; 
} 

यह या आपके उपयोग के मामले में उपयोगी नहीं हो सकता है हो सकता है।

संबंधित मुद्दे