You start with this array:
my @array = 1..10;
Now you have an array of 10 elements.
1 2 3 4 5 6 7 8 9 10
In your next step, you perform an array slice then assign that to another array slice:
@array[0..3] = @array[5..8];
This leaves alone the elements from 5 to 8, but does a list assignment of their values to the elements from 0 to 3, so you end up with some duplicated elements:
6 7 8 9 5 6 7 8 9 10
Now you want to get rid of everything after index 4. You try that with another list assignment:
@array[4..10] = ();
However, that just assigns the list on the right to the list on the right. As with any list assignment, the left hand elements get their corresponding elements from the right hand list. If the right hand list doesn't have enough elements, Perl uses undef for the rest of the right hand elements. That's why you still have 10 elements in @array:
6 7 8 9 undef undef undef undef undef undef undef
If you want 4 to be the last index, you can assign to the last index of the array. Whatever number you assign becomes the last index, either shortening or extending the array. Since you wanted to get rid of elements 4 and beyond, you can set the last index to 3 (the index right before the one you want to remove):
$#array = 3;
Now you've truncated the array to four elements:
6 7 8 9
You can also do this with splice, which replaces part of an array:
splice @array, $start_index, $length, @replacement;
You might use the starting index to figure out the length since you want to go all the way to the end. Then, replace that portion of the array with the empty list, which effectively makes the array shorter:
my $start = 4;
splice @array, $start, @array - $start, ();
Leaving off the replacement list is the same as the empty list:
splice @array, $start, @array - $start;
This is much more handy when you want to remove parts in the middle. This removes three elements starting at index 4 (so there will be stuff left over at the end):
splice @array, 4, 3;
Now your array has elements that were at the beginning and end of your array:
6,7,8,9,8,9,10
Without shortening the array
There's another sort of problem. You don't want to change the array, but you don't want to deal with empty fields. You can use a grep to select only the defined elements:
say join ',', grep { defined } @array;
If you have undefined elements in the middle of the array, this might be a problem if you expect columns to line up properly. Removing a column in the middle shifts the other columns. You may not care about that though.
Similarly, you might turn the undefined values into something that makes sense for the problem. A map can inspect the value and decide to pass it through or transform it. In this example, undef values turn into 0:
say join ',', map { defined ? $_ : 0 } @array;
6,7,8,9,0,0,0,0,0,0,0
Or "NULL":
say join ',', map { defined ? $_ : 'NULL' } @array;
6,7,8,9,NULL,NULL,NULL,NULL,NULL,NULL,NULL
Or even just undef as a string:
say join ',', map { defined ? $_ : 'undef' } @array;
6,7,8,9,undef,undef,undef,undef,undef,undef,undef
Sometimes those are handy to see what's going on.
And map can act like grep to filter an array. Use the empty list to pass on no elements from the map:
say join ',', map { defined ? $_ : () } @array;