in reply to extracting a list element

Using delete for arrays is almost always wrong, and it's documented:

> delete may also be used on arrays and array slices, but its behavior is less straightforward. Although " exists" will return false for deleted entries, deleting array elements never changes indices of existing values ; use shift or splice for that.

DB<8> $a[0][0] = ['00', '01']; DB<9> $a[0][1] = ['10', '11']; DB<10> x splice @{$a[0]},0,1 0 ARRAY(0xb40000795febe168) 0 00 1 01 DB<11> x @a 0 ARRAY(0xb40000795febbdf8) 0 ARRAY(0xb40000795fee4240) 0 10 1 11 DB<12>

Cheers Rolf
(addicted to the Perl Programming Language :)
see Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re^2: extracting a list element
by geoffleach (Scribe) on Jan 05, 2024 at 18:53 UTC
    Thanks Rolf and Annon.
Re^2: extracting a list element
by jo37 (Curate) on Jan 06, 2024 at 13:40 UTC
    Using delete for arrays is almost always wrong...

    I disagree. Deleting an array slice is a very handy operation that I don't regard as useful almost never.

    my @a = (2 .. 9); my @i = (2, 3, 5); delete @a[@i]; my @b = grep defined, @a;

    Greetings,
    -jo

    $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
      A much saner way to undefine slices is @a[@i] = () ° ¹

      DB<26> @a = (2 .. 9); DB<27> @i = (2, 3, 5); DB<28> @a[@i] = () DB<29> @b = grep defined, @a; DB<30> x @a 0 2 1 3 2 undef 3 undef 4 6 5 undef 6 8 7 9 DB<31> x @b 0 2 1 3 2 6 3 8 4 9 DB<32> ... DB<65> p exists $a[0] 1 DB<66> p defined $a[0] DB<67>

      Like with hashes is delete not assigning undef but kicking the element's value out of existence.

      Now the size of hashes is shrinking by the number of deleted elements. But with arrays this only happens for elements at the end of the array, which is shortened then. While this is consistent with the use of exists , it might lead to unpredictable behavior.*

      This explains the stark warning.

      DB<40> @a = (0..4) DB<41> delete @a[0,2,4] DB<42> p exists $a[0] DB<43> p exists $a[1] 1 DB<44> x @a # shortened 0 undef 1 1 2 undef 3 3 DB<45> p scalar @a 4 DB<46>

      Bottom line: only use delete with arrays if you really want to differentiate between defined and exists and this shrinking behavior is anticipated.

      In order to remove array elements use splice. If you need sparse arrays, consider using hashes with numbers as keys. *

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

      footnotes

      °) unfortunately is undef @arr[@slice] not DWIM.

      *) Paragraph rephrased

      ¹) and @b = grep exists, @a; is the way to go together with delete. This way you won't get caught by accidental undef values.

      update

      To better highlight that undef is an existing value but non existence is translated to undef after assignment:

      DB<56> x @a 0 undef 1 1 2 undef 3 3 DB<57> $a[5] = undef DB<58> x @a 0 undef 1 1 2 undef 3 3 4 undef. # gap 5 undef. # value DB<59> p exists $a[4] DB<60> p exists $a[5] 1 DB<61>

      From delete

      WARNING: Calling delete on array values is strongly discouraged. The notion of deleting or checking the existence of Perl array elements is not conceptually coherent, and can lead to surprising behavior.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery