วิธีที่เร็วที่สุดในการแปลงสตริงเป็นจำนวนเต็มใน PHP


251

ใช้ PHP วิธีที่เร็วที่สุดในการแปลงสตริงเช่นนี้"123"เป็นจำนวนเต็มคืออะไร

เหตุใดจึงเป็นวิธีที่เร็วที่สุด? จะเกิดอะไรขึ้นหากได้รับอินพุตที่ไม่คาดคิดเช่น"hello"หรืออาร์เรย์


12
ดีถ้าไม่เจ็บ (อ่านง่าย) ทำไมไม่ทำสิ่งต่าง ๆ ในวิธีที่มีประสิทธิภาพที่สุดเท่าที่จะทำได้?
nickf

19
ถ้ามันไม่เจ็บความเร็วทำไมไม่ทำสิ่งต่าง ๆ ในทางที่อ่านได้มากที่สุด?
Andy Lester

4
@Andy ดูการทดสอบมาตรฐานด้านล่าง ความแตกต่างระหว่าง(int)และintval()สามารถมากกว่า 400%!
nickf

6
เรื่องที่เร็วที่สุดเพราะเรื่องความเร็วสำหรับประสบการณ์ของผู้ใช้ เมื่อคุณมีปฏิบัติการหลายอย่างเกิดขึ้นคุณต้องการให้มันทำงานได้อย่างรวดเร็ว!
philipp

13
โดยไม่ต้องเตะม้าที่ตายแล้วฉันจะบอกว่าคำถามเกี่ยวกับความเร็วในการอ่านและการอ่านนั้นไม่เกี่ยวข้องในกรณีนี้เพราะคำถามถูกติดแท็กภายใต้การปรับให้เหมาะสม เหตุผลที่ต้องการความเร็วในคำถามที่ติดแท็กภายใต้การปรับให้เหมาะสมคือการอธิบายตนเอง
totalNotLizards

คำตอบ:


371

ฉันเพิ่งตั้งค่าการเปรียบเทียบอย่างรวดเร็ว:

Function             time to run 1 million iterations
--------------------------------------------
(int) "123":                0.55029
intval("123"):              1.0115  (183%)

(int) "0":                  0.42461
intval("0"):                0.95683 (225%)

(int) int:                  0.1502
intval(int):                0.65716 (438%)

(int) array("a", "b"):      0.91264
intval(array("a", "b")):    1.47681 (162%)

(int) "hello":              0.42208
intval("hello"):            0.93678 (222%)

โดยเฉลี่ยแล้วการโทรภายใน () คือช้าลงสองเท่าครึ่งและความแตกต่างนั้นยิ่งใหญ่ที่สุดหากอินพุตของคุณเป็นจำนวนเต็ม

ฉันจะสนใจที่จะรู้ว่าทำไมแม้ว่า


อัปเดต: ฉันได้ทำการทดสอบอีกครั้งคราวนี้ด้วยการบีบบังคับ (0 + $var)

| INPUT ($x)      |  (int) $x  |intval($x) |  0 + $x   |
|-----------------|------------|-----------|-----------|
| "123"           |   0.51541  |  0.96924  |  0.33828  |
| "0"             |   0.42723  |  0.97418  |  0.31353  |
| 123             |   0.15011  |  0.61690  |  0.15452  |
| array("a", "b") |   0.8893   |  1.45109  |  err!     |
| "hello"         |   0.42618  |  0.88803  |  0.1691   |
|-----------------|------------|-----------|-----------|

ภาคผนวก:ฉันเพิ่งเจอพฤติกรรมที่ไม่คาดคิดเล็กน้อยซึ่งคุณควรระวังเมื่อเลือกวิธีใดวิธีหนึ่งต่อไปนี้:

$x = "11";
(int) $x;      // int(11)
intval($x);    // int(11)
$x + 0;        // int(11)

$x = "0x11";
(int) $x;      // int(0)
intval($x);    // int(0)
$x + 0;        // int(17) !

$x = "011";
(int) $x;      // int(11)
intval($x);    // int(11)
$x + 0;        // int(11) (not 9)

ผ่านการทดสอบโดยใช้ PHP 5.3.1


9
มันอาจจะมีบางอย่างเกี่ยวข้องกับความจริงที่ว่า intval () เรียกการเรียกใช้ฟังก์ชันในขณะที่นักแสดงได้รับการจัดการโดยตรงในเครื่องคิดเลขนิพจน์ของล่าม นี่อาจเป็นเหตุผลที่การบังคับคดีเร็วขึ้น
staticsan

10
ตัวอย่างการบีบบังคับของคุณสามารถทำให้ง่ายขึ้นโดยใช้ unary plus operator ที่เป็นที่รู้จักของ php $ x + 0 -> + $ x
Ozzy

@Ozzy มันยอดเยี่ยมมาก ขอบคุณสำหรับทิป! +"15" == 15
caiosm1005

1
@ John ตั้งแต่เขาทดสอบเพียงสองกรณีในรหัสแรกที่(int)และintvalและในแต่ละคู่ให้% ในกรณีฐานจะต้องintval (int)แต่คุณมีจุดที่ดีที่มันจะชัดเจนขึ้นถ้าเขาพูดอย่างชัดเจนโดยเฉพาะอย่างยิ่งเมื่อเขาเพิ่มกรณีที่สามในภายหลัง!
ToolmakerSteve

2
มีการเปลี่ยนแปลงใด ๆ กับผลลัพธ์นี้ในเวอร์ชัน PHP ที่ใหม่กว่าหรือไม่
Artyom

34

โดยส่วนตัวแล้วฉันรู้สึกว่าการคัดเลือกนักแสดงที่สวยที่สุด

$iSomeVar = (int) $sSomeOtherVar;

หากส่งสตริงเช่น 'Hello' มันจะถูกแปลงเป็นจำนวนเต็ม 0 สำหรับสตริงเช่น '22 ปี 'สตริงนั้นจะถูกแปลงเป็นจำนวนเต็ม 22 สิ่งใดที่ไม่สามารถแยกเป็นตัวเลขได้จะกลายเป็น 0

หากคุณต้องการความเร็วจริงๆฉันเดาว่าคำแนะนำอื่น ๆ ที่นี่ถูกต้องโดยถือว่าการข่มขู่นั้นเร็วที่สุด


7
ที่น่าสนใจอาร์เรย์ได้รับการโยนไป 1 ไปคิด
nickf

2
@nickf Not so - มันสามารถร่ายเป็น 0 ได้เช่นกัน มันจะปลดเปลื้องมันเป็นค่าบูลีน (จริง | เท็จ) เป็นจำนวนเต็ม - 'เท็จ' = 0, 'จริง' = 1 อาร์เรย์เป็นเท็จถ้ามันว่างเปล่า 100% และเป็นจริงถ้ามันมีข้อมูลใด ๆ แม้ว่ามันจะว่างเปล่า สตริงหรือค่า NULL หากคุณต้องส่งอาเรย์ที่ว่างเปล่าให้เป็นจำนวนเต็มมันจะกลายเป็น 0 (ใช่ฉันรู้แล้วว่ามันเก่า!)
Super Cat

15

ทำการทดสอบ

   string coerce:          7.42296099663
   string cast:            8.05654597282
   string fail coerce:     7.14159703255
   string fail cast:       7.87444186211

นี่คือการทดสอบที่วิ่งในแต่ละสถานการณ์ 10,000,000 ครั้ง :-)

เพื่อนร่วมงานคือ 0 + "123"

การคัดเลือกนักแสดงคือ (integer)"123"

ฉันคิดว่า Co-ercion เร็วกว่านิดหน่อย โอ้และพยายาม0 + array('123')เป็นข้อผิดพลาดร้ายแรงใน PHP คุณอาจต้องการรหัสของคุณเพื่อตรวจสอบประเภทของค่าที่ให้มา

รหัสทดสอบของฉันอยู่ด้านล่าง


function test_string_coerce($s) {
    return 0 + $s;
}

function test_string_cast($s) {
    return (integer)$s;
}

$iter = 10000000;

print "-- running each text $iter times.\n";

// string co-erce
$string_coerce = new Timer;
$string_coerce->Start();

print "String Coerce test\n";
for( $i = 0; $i < $iter ; $i++ ) {
    test_string_coerce('123');
}

$string_coerce->Stop();

// string cast
$string_cast = new Timer;
$string_cast->Start();

print "String Cast test\n";
for( $i = 0; $i < $iter ; $i++ ) {
    test_string_cast('123');
}

$string_cast->Stop();

// string co-erce fail.
$string_coerce_fail = new Timer;
$string_coerce_fail->Start();

print "String Coerce fail test\n";
for( $i = 0; $i < $iter ; $i++ ) {
    test_string_coerce('hello');
}

$string_coerce_fail->Stop();

// string cast fail
$string_cast_fail = new Timer;
$string_cast_fail->Start();

print "String Cast fail test\n";
for( $i = 0; $i < $iter ; $i++ ) {
    test_string_cast('hello');
}

$string_cast_fail->Stop();

// -----------------
print "\n";
print "string coerce:          ".$string_coerce->Elapsed()."\n";
print "string cast:            ".$string_cast->Elapsed()."\n";
print "string fail coerce:     ".$string_coerce_fail->Elapsed()."\n";
print "string fail cast:       ".$string_cast_fail->Elapsed()."\n";


class Timer {
    var $ticking = null;
    var $started_at = false;
    var $elapsed = 0;

    function Timer() {
        $this->ticking = null;
    }

    function Start() {
        $this->ticking = true;
        $this->started_at = microtime(TRUE);
    }

    function Stop() {
        if( $this->ticking )
            $this->elapsed = microtime(TRUE) - $this->started_at;
        $this->ticking = false;
    }

    function Elapsed() {
        switch( $this->ticking ) {
            case true: return "Still Running";
            case false: return $this->elapsed;
            case null: return "Not Started";
        }
    }
}

ฉันเพิ่มลงsettypeในการทดสอบนี้และรันโดยใช้ PHP 7. การส่งออกมาด้านหน้าเล็กน้อยและการปรับปรุงประสิทธิภาพที่ใหญ่กว่าทั้งหมด: การรวมสตริง: 1.9255340099335 การโยนสตริง: 1.5142338275909 สตริงการตั้งค่าประเภท: 4.149735212326 สตริงการทดสอบล้มเหลว: 1.2346560955048 settype: 4.149735212326
bstoney

9

คุณสามารถแปลงสตริงแบบยาวเป็นจำนวนเต็มได้โดยใช้ FLOAT

$float = (float)$num;

หรือถ้าคุณต้องการจำนวนเต็มไม่ลอย val แล้วไปกับ

$float = (int)$num;

สำหรับอดีต

(int)   "1212.3"   = 1212 
(float) "1212.3"   = 1212.3

1
ฮะ? หากคุณต้องการเป็น int, ทำไมคุณจะไม่ใช้(int)? มันอาจจะเป็นความจริงที่ว่าถ้าสตริงมีจำนวนเต็มมัน(float)จะคืนค่าที่ทำหน้าที่เหมือนจำนวนเต็ม (แม้ว่ามันอาจจะเป็นประเภทภายในfloat) แต่ทำไมคุณต้องทำเช่นนี้ถ้าข้อมูลจำเพาะคือการคืนค่าจำนวนเต็ม ? สมมติว่าสตริงที่เข้ามาคือ "1.3"? คุณจะไม่ได้รับจำนวนเต็ม นอกจากนี้เพื่อใครก็ตามที่อ่านรหัสในอนาคตคุณควรพูดในสิ่งที่คุณหมายถึง หากคุณหมายถึง "ควรเป็นจำนวนเต็ม" ดังนั้น(int)อย่า(float)พูด
ToolmakerSteve

7
$int = settype("100", "integer"); //convert the numeric string to int

3
ฉันเชื่อว่ามีการอ้างอิงหรือหลักฐานอยู่ในลำดับ!
Mehran

$ int จะเป็นบูลีนจริง ๆ ถ้าคำสั่งใช้งานได้ แต่จะไม่นับตั้งแต่พารามิเตอร์แรกของ settype () ถูกส่งผ่านโดยการอ้างอิงดังนั้นต้องเป็น var
คิว

7

จำนวนเต็มยกเว้นจากสตริงใด ๆ

$ in = 'tel.123-12-33';

preg_match_all('!\d+!', $in, $matches);
$out =  (int)implode('', $matches[0]);

// $ out = '1231233';


คุณคือสุดยอดฝีมือที่สุด! ฉันใช้เวลาหลายชั่วโมงในการแปลง var จากสตริงข้อมูล json เป็นจำนวนเต็มวิธีการของคุณช่วยได้! ขอบคุณ!
Kamnibula

4

ผลลัพธ์เกณฑ์มาตรฐานเฉพาะกิจเพิ่มเติม:

$ time php -r 'for ($x = 0;$x < 999999999; $x++){$i = (integer) "-11";}'     

real    2m10.397s
user    2m10.220s
sys     0m0.025s

$ time php -r 'for ($x = 0;$x < 999999999; $x++){$i += "-11";}'              

real    2m1.724s
user    2m1.635s
sys     0m0.009s

$ time php -r 'for ($x = 0;$x < 999999999; $x++){$i = + "-11";}'             

real    1m21.000s
user    1m20.964s
sys     0m0.007s

มันจะเป็นการดีกว่าถ้าคุณเขียนคำสั่งที่ถูกทดสอบ 10x ในแต่ละลูปดังนั้นเวลาจะไม่ถูกครอบงำโดยโอเวอร์เฮดของลูป { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }เช่น นอกจากนี้ยังมีความเสี่ยงที่จะใช้ค่าตัวอักษร"-11"โดยตรงเว้นแต่คุณจะแน่ใจว่าภาษาจะไม่ทำงานบางอย่างในเวลารวบรวม อาจตกลงสำหรับภาษาแบบไดนามิกเช่น PHP แต่ฉันพูดถึงสำหรับการอ้างอิงในอนาคตถ้าทดสอบสูตรในภาษาอื่น ๆ ปลอดภัยกว่าในการตั้งค่าตัวแปร$x = "-11"ก่อนการทดสอบลูปจากนั้นใช้ $i =+$xเพื่อให้รหัสภายในคือ
ToolmakerSteve

4

วิ่งเกณฑ์มาตรฐานและมันกลับกลายเป็นวิธีที่เร็วที่สุดในการรับจำนวนเต็มจริง (โดยใช้วิธีที่มีอยู่ทั้งหมด) คือ

$foo = (int)+"12.345";

เพียงแค่ใช้

$foo = +"12.345";

ผลตอบแทนลอย


2
มันเร็วกว่า(int)"12.345"หรือเปล่า? เร็วขึ้นตามเปอร์เซ็นต์อะไร
ToolmakerSteve
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.