Deleting elements in a perl array without index - arrays

I have an array which contains several strings. There is another array which contains strings which may or may not be contained in the first array.
What is the best way to remove any instances of a string in array b from the strings in array a. I have tried to use grep as in the example below but it completely empties the array.
my #Aray = ('Chris', 'John', 'Paul', 'Max', 'Jim', 'John');
my #Bray = ('Chris', 'John');
foreach $name (#Bray){
#Aray = grep {$_ != $name} #Aray;
}
This would result in no elements left in #Aray, opposed to 'Paul', 'Max', 'Jim'
I also tried with a traditional for loop and indexing each name in #Bray with the same result.

#choroba shows above how to solve the specific problem you are asking.
Deleting elements of one array based on the elements on another is a common problem in Perl, and there is a useful idiom that speeds up such operations. Specifically:
Place the elements you want to delete (Array B) in a Hash H.
Loop over Array A and test whether any of its elements are in Hash H, if so delete them, otherwise keep them
This method has the benefit of only reading the delete array (Array B) a single time instead of for every element of Array A
my #Aray = ('Chris', 'John', 'Paul', 'Max', 'Jim', 'John');
my #Bray = ('Chris', 'John');
my %to_delete = map { $_ => 1 } #Bray;
#Aray = grep { ! $to_delete{$_} } #Aray;

Related

Get the index of the last occurrence of each string in an array

I have an array that is storing a large number of various names in string format. There can be duplicates.
let myArray = ["Jim","Tristan","Robert","Lexi","Michael","Robert","Jim"]
In this case I do NOT know what values will be in the array after grabbing the data from a parse server. So the data imported will be different every time. Just a list of random names.
Assuming I don't know all the strings in the array I need to find the index of the last occurrence of each string in the array.
Example:
If this is my array....
let myArray = ["john","john","blake","robert","john","blake"]
I want the last index of each occurrence so...
blake = 5
john = 4
robert = 3
What is the best way to do this in Swift?
Normally I would just make a variable for each item possibility in the array and then increment through the array and count the items but in this case there are thousands of items in the array and they are of unknown values.
Create an array with elements and their indices:
zip(myArray, myArray.indices)
then reduce into a dictionary where keys are array elements and values are indices:
let result = zip(myArray, myArray.indices).reduce(into: [:]) { dict, tuple in
dict[tuple.0] = tuple.1
}
(myArray.enumerated() returns offsets, not indices, but it would have worked here too instead of zip since Array has an Int zero-based indices)
EDIT: Dictionary(_:uniquingKeysWith:) approach (#Jessy's answer) is a cleaner way to do it
New Dev's answer is the way to go. Except, the standard library already has a solution that does that, so use that instead.
Dictionary(
["john", "john", "blake", "robert", "john", "blake"]
.enumerated()
.map { ($0.element, $0.offset) }
) { $1 }
Or if you've already got a collection elsewhere…
Dictionary(zip(collection, collection.indices)) { $1 }
Just for fun, the one-liner, and likely the shortest, solution (brevity over clarity, or was it the other way around? :P)
myArray.enumerated().reduce(into: [:]) { $0[$1.0] = $1.1 }

How can I remove an item in a Ruby array based on its content?

I'm making a sort of variable system in Ruby where a user can create a variable. Provided they give a variable name and contents, it adds the name and string given to an array, adding two more items to the array. Here's the code:
$vars = []
def create(name, value)
$vars << name
$vars << value
end
I also want to add a "delete" option where the user types delete("varName") and behind the scenes, it searches for an item with the same value in the $vars array and deletes it. Is there any way to do this? Also, is there any way to get the number of the item (e.g. items in the array are ["a", "b", "c", "d"] and the user wants to delete "d",and then the program returns 3, since that's the location of "d".
A Hash is used to store pairs of items. It is faster, and guarantees names will be unique.
$vars = {}
def create(name, value)
$vars[name] = value
end
Then deleting is trivial.
$vars.delete(name)
As is finding the value.
value = $vars[name]
Hashes remember the order in which keys were added. $vars.keys will return an Array of the names in the order they were added. Then you can use find_index to get where it appears in the list of keys.
index = $vars.keys.find_index(name)
Aside from letting the user know the order in which variables are declared, this isn't of much use. Variables don't have an order.
If you wanted to do this with arrays, first we'd fix create. It's storing both the key and the value in the same Array.
create(a, 23)
create(b, 42)
# $var = ['a', 23, 'b', 42]
Instead, store each pair in its own array.
def create(name, value)
$vars << [name, value]
end
create(a, 23)
create(b, 42)
# $var = [['a', 23], ['b', 42]]
Then to delete, search just the first elements of each pair using index. Then delete that index.
def delete(name)
idx = $vars.map(&:first).index(name)
$vars.delete_at(idx) if idx
return idx
end
Finding the value of a name would work similarly. Find the index of the matching name, look up that pair, return its second element (the value).
def find(name)
idx = $vars.map(&:first).index(name)
pair = $vars[idx]
return pair[1]
end
But don't do this, use a Hash.
$vars = ["name", "value", "item"]
index = $vars.index("name")
$vars.delete_at(index)
Sources:
Duplicate?
Editor
Documentation
Although if this is rails, is it really a good idea to use a GLOBAL variable?

Perl assign array to hash and vice-versa

I would like to get your help to figure out how to add a long array to a hash key value, how to assign the key value to a temporay array from where the data will be manipulated, than assign the array (or what I have left) back to the same hash key.
A sample of what I am looking for is below:
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
My set of arrays that will contain only integers
my #Array1 = ['01', '02', '03', '04', '09', '10', '11', '12'];
my #Array2 = ['05', '06', '07', '08', '03', '04', '09'];
my #Array3 = ['09', '10', '11', '12', '02', '03', , '07', '08' ];
my #ArrayN = ['N', 'N', 'N', 'N'];
My hash with keys identified by integers (Is it possible?)
my %Hash;
Assigning arrays to key values;
%Hash{'1'} = #Array1 (or $Array1);
%Hash{'2'} = #Array2 (or $Array2);
%Hash{'3'} = #Array3 (or $Array3);
%Hash{'N'} = #ArrayN (or $ArrayN);
Assign a hash key value to a temporary array
my #TempArray = $Hash{'1'};
Some process with the temporary array including:
(Delete the first element/item of the temporary array, let's say the
numnber "01"');
(Check if the array has a especifc value, let's say numbers 03 and
09);
(Delete especific values from the array, let's say the
numnbers 03 and 09');
(Check how many elements/items exist in the array);
than assign the value back to the hash
%Hash{'1'} = #TempArray;
I have found many posts that are not helping so much, as they don't talk about long arrays.
By using square brackets for your lists, you've actually created an array reference, which is a scalar. Your assignments should thus be:
my $Array1 = ['01', '02', '03', '04', '09', '10', '11', '12'];
my $Array2 = ['05', '06', '07', '08', '03', '04', '09'];
etc.
Next, when assigning these references as hash keys, you must use the $ sigil since you're referring to the hash value (a scalar) and not the hash itself.
$Hash{'1'} = $Array1;
$Hash{'2'} = $Array2;
Now if you want to assign these references to array variables, you must dereference them:
my #TempArray = #{ $Hash{'1'} };
As for your list of operations/checks on these arrays:
Delete the first item:
shift #TempArray;
Check if a certain value is an element of the array:
my $check = grep { $_ == $some_number } #TempArray;
($check will be the number of matches returned, and thus will evaluate to false if you get zero matches);
Delete an specific element (index unknown) from the array:
Every occurrence of a certain value?
#TempArray = grep { $_ != $some_number } #TempArray;
A specific element (not necessarily first or last)? Need to know the offset.
splice #TempArray => $index;
Check the length of the array:
my $length = #TempArray;
(referring to an array in list context returns its length)
My set of arrays that will contain only integers
Actually, your arrays contain strings :-)
my #Array1 = ['01', '02', '03', '04', '09', '10', '11', '12'];
Here's your first serious error. Arrays are initialised from lists - so you need round brackets, (...), not square brackets, [...].
You wanted this:
my #Array1 = ('01', '02', '03', '04', '09', '10', '11', '12');
Alternatively, you could use your original square brackets. But they give you an array reference. A reference is a scalar value, so you store it in a scalar variable.
my $Array1_ref = ['01', '02', '03', '04', '09', '10', '11', '12'];
My hash with keys identified by integers (Is it possible?)
Well, the keys of a hash are always strings. But that's ok. Perl will seamlessly convert integers to strings. And it's not necessary here because you're actually using strings ('1'), not integers (1).
%Hash{'1'} = #Array1;
A couple of errors here. The values in a hash are scalars. So you access them using a scalar sigil ($, not %). And, of course, an array isn't a scalar so you can't store it in a hash value. You can, however, store an array reference in a hash value (as references are scalar values.
$Hash{'1'} = \#Array1; # use \ to get a reference
Alternatively, if you stuck with the [...] version and stored your array reference in $Array_ref, then you can do:
$Hash{'1'} = $Array_ref;
Assign a hash key value to a temporary array
The value in your hash is a reference to your array. So you need to dereference it before storing it in an array variable.
#Temp_Array = #{ $Hash{'1'} };
Delete the first element/item of the temporary array, let's say the numnber "01"'
shift #Temp_Array;
Check if the array has a especifc value, let's say numbers 03 and 09
if (grep { $_ eq '03' } #Temp_Array) {
say "03 is in the array";
}
Delete especific values from the array, let's say the numnbers 03 and 09
#Temp_Array = grep { $_ ne '03' and $_ ne '09' } #Temp_Array;
Check how many elements/items exist in the array
Simply evaluate the array in a scalar expression.
$num_of_elements = #Temp_Array;
then assign the value back to the hash
Once again, you need to take a reference to the array.
$Hash{'1'} = \#Temp_Array
It's worth pointing out that you don't need to copy the array to a temporary array variable in order to manipulate it. Anywhere that I have used #Temp_Array in the examples above, you can replace it with #{ $Hash{'1'} } and you will be manipulating the array inside the hash directly.
shift #{ $Hash{'1'} }; # for example
I have found many posts that are not helping so much, as they don't talk about long arrays.
That's probably because long arrays and short arrays (and middle-sized arrays) are all handled in exactly the same way in Perl.

What is the difference between lists and arrays?

On this page, it shows how to initialize an array, and if you scroll down a bit, under the section called "The Lists" it "explains" what lists are and how they're different from arrays.
Except it uses an example that's just exactly the same as declaring an array, and doesn't explain it whatsoever.
What is the difference?
Take a look at perldoc -q "list and an array". The biggest difference is that an array is a variable, but all of Perl's data types (scalar, array and hash) can provide a list, which is simply an ordered set of scalars.
Consider this code
use strict;
use warnings;
my $scalar = 'text';
my #array = (1, 2, 3);
my %hash = (key1 => 'val1', key2 => 'val2');
test();
test($scalar);
test(#array);
test(%hash);
sub test { printf "( %s )\n", join ', ', #_ }
which outputs this
( )
( text )
( 1, 2, 3 )
( key2, val2, key1, val1 )
A Perl subroutine takes a list as its parameters. In the first case the list is empty; in the second it has a single element ( $scalar); in the third the list is the same size as #array and contains ( $array[0], $array[1], $array[2], ...), and in the last it is twice as bug as the number of elements in %hash, and contains ( 'key1', $hash{key1}, 'key2', $hash{key2}, ...).
Clearly that list can be provided in several ways, including a mix of scalar variables, scalar constants, and the result of subroutine calls, such as
test($scalar, $array[1], $hash{key2}, 99, {aa => 1, bb => 2}, \*STDOUT, test2())
and I hope it is clear that such a list is very different from an array.
Would it help to think of arrays as list variables? There is rarely a problem distinguishing between scalar literals and scalar variables. For instance:
my $str = 'string';
my $num = 99;
it is clear that 'string' and 99 are literals while $str and $num are variables. And the distinction is the same here:
my #numbers = (1, 2, 3, 4);
my #strings = qw/ aa bb cc dd /;
where (1, 2, 3, 4) and qw/ aa bb cc dd / are list literals, while #numbers and #strings are variables.
Actually, this question is quite well answered in Perl's FAQ. Lists are (one of) methods to organize the data in the Perl source code. Arrays are one type of storing data; hashes are another.
The difference is quite obvious here:
my #arr = (4, 3, 2, 1);
my $arr_count = #arr;
my $list_count = (4, 3, 2, 1);
print $arr_count, "\n"; # 4
print $list_count; # 1
At first sight, there are two identical lists here. Note, though, that only the one that is assigned to #arr variable is correctly counted by scalar assignment. The $list_count stores 1 - the result of evaluating expression with comma operator (which basically gives us the last expression in that enumeration - 1).
Note that there's a slight (but very important) difference between list operators/functions and array ones: the former are kind-of omnivores, as they don't change the source data, the latter are not. For example, you can safely slice and join your list, like this:
print join ':', (4,2,3,1)[1,2];
... but trying to 'pop' it will give you quite a telling message:
pop (4, 3, 2, 1);
### Type of arg 1 to pop must be array (not list)...
An array is a type of variable. It contains 0 or more scalars at monotonously increasing indexes. For example, the following creates array #a:
my #a;
Being variables, you can manipulate arrays. You can add elements, change the values of elements, etc.
"List" means many things. The two primary uses for it are to refer to list values and instances of the list operator.
A list value is an ordered collection of zero or more scalars on the stack. For example, the sub in the following code returns a list to be assigned to #a (an array).
my #a = f();
List values can't be manipulated; they are absorbed in whole by any operator to which they are passed. They are just how values are passed between subs and operators.
The list operator (,) is an N-ary operator* that evaluates each of its operands in turn. In list context, the list operator returns a list consisting of an amalgamation of the lists returned by its operands. For example, the list operator in the following snippet returns a list value consisting of all the elements of arrays #a and #b:
my #c = ( #a, #b );
(By the way, parens don't create lists. They're just there to override precedence.)
You cannot manipulate a list operator since it's code.
* — The docs say it's a binary operator (at least in scalar context), but it's not true.
Simple demonstration of difference.
sub getarray{ my #x = (2,4,6); return #x; }
sub getlist { return (2,4,6); }
Now, if you do something like this:
my #a = getarray();
my #b = getlist();
Then #a and #b will both contain the same value - the list (2,4,6). However, if you do this:
my $a = getarray();
my $b = getlist();
Then $a will contain the value 3, while $b will contain the value 6.
So yes, you can say that arrays are variables containing list values, but that doesn't tell the whole story, because arrays and literal lists behave quite differently at times.
Lists are comma-separated values (csv) or expressions (cse) . Arrays (and hashes) are containers.
One can initialize an array or hash by a list:
#a = ("profession", "driver", "salary", "2000");
%h = ("profession", "driver", "salary", "2000");
One can return a list:
sub f {
return "moscow", "tel-aviv", "madrid";
}
($t1, $t2, $t3) = f();
print "$t1 $t2 $t3\n";
($t1, $t2, $t3) is a list of scalar containers $t1, $t2, $t3.
Lists are a form of writing perl expressions (part of syntax) while arrays are data structures (memory locations).
The difference between lists and arrays confuses many. Perl itself got it wrong by misnaming its builtin function wantarray(): "This function should have been named wantlist() instead." There is an answer in perlfaq4, "What is the difference between a list and an array?", but it did not end my confusion.
I now believe these to be true:
An array in scalar context becomes a count of its elements.
The comma operator in scalar context returns the last element.
You can't make a reference to a list; \(2, 4, 6) returns a list of references to the scalars in the list. You can use [2, 4, 6] to make a reference to an anonymous array.
You can index a list (to get its nth element) without making an array if you make a list slice, so (2, 4, 6)[1] is 4.
But what if I want to count the elements in a list, or get the last element of an array? Should I convert between arrays and lists somehow?
You can always convert a list to an array with [...] syntax. One way to count the elements in a list is to make an anonymous array, then immediately dereference it in scalar context, like so:
sub list { return qw(carrot stick); }
my $count = #{[list()]};
print "Count: $count\n"; # Count: 2
Another way is to use the list assignment operator, like so:
sub list { return qw(carrot stick); }
my $count = (()=list());
print "Count: $count\n"; # Count: 2
There is no array in this code, but the list assignment operator returns the number of things being assigned. I assign them to an empty list of variables. In code golf, I write ()=$str=~/reg/g to count the regular expression matches in some string.
You need not convert an array to a list, because an array in list context is already a list. If you want the last element of an array, just say $array[-1].
The comma operator would return the last element of a list, but I can't use it to get the last element of an array. If I say ((),#array) in scalar context, then #array is in scalar context and I get the count.
You need not make an array to index a list. You can make an anonymous array, as in [list()]->[1], or you can make a list slice, as in (list())[1]. I had trouble with list slices because they have different syntax. A list slice needs parentheses! In C or Python or Ruby, func()[1] would do the array index on the function's return value, but in Perl, func()[1] is a syntax error. You must say (func())[1].
For example, I want to print the 3rd highest number in array. Because I'm lazy, I sort the array and take the 3rd last element:
my #array = (112, 101, 114, 108, 32, 104, 97, 99, 107);
print +(sort { $a <=> $b } #array)[-3], "\n"; # prints 108
The unary + prevents the print() function stealing my parentheses.
You can use a list slice on an array, as in (#array)[1]. This works because an array is a list. The difference between lists and arrays is that arrays can do $array[1].
An Array Vs A List
A list is a different kind of data structure from an array.
The biggest difference is in the idea of direct access Vs sequential access. Arrays allow both; direct and sequential access, while lists allow only sequential access. And this is because the way that these data structures are stored in memory.
In addition, the structure of the list doesn’t support numeric index like an array is. And, the elements don’t need to be allocated next to each other in the memory like an array is.
Arrays
An array is an ordered collection of items, where each item inside the array has an index.
here my answer about sigils and context
but main difference is this:
arrays have a scalar-context-value like count of elements.
lists have a scalar-context-value like LAST element in list.
so, you need to know about goat-operator: =()=.
Usage?
perl -e '$s =()= qw(a b c); print $s' # uh? 3? (3 elements, array context)
perl -e '$s = qw(a b cLastElementThatYouSee); print $s' # uh? cLastElementThatYouSee? (list context, last element returned)
as you see, =()= change context to array

Filling hash of multi-dimensional arrays in perl

Given three scalars, what is the perl syntax to fill a hash in which one of the scalars is the key, another determines which of two arrays is filled, and the third is appended to one of the arrays? For example:
my $weekday = "Monday";
my $kind = "Good";
my $event = "Birthday";
and given only the scalars and not their particular values, obtained inside a loop, I want a hash like:
my %Weekdays = {
'Monday' => [
["Birthday", "Holiday"], # The Good array
["Exam", "Workday"] # The Bad array
]
'Saturday' => [
["RoadTrip", "Concert", "Movie"],
["Yardwork", "VisitMIL"]
]
}
I know how to append a value to an array in a hash, such as if the key is a single array:
push( #{ $Weekdays{$weekday} }, $event);
Used in a loop, that could give me:
%Weekdays = {
'Monday' => [
'Birthday',
'Holiday',
'Exam',
'Workday'
]
}
I suppose the hash key is the particular weekday, and the value should be a two dimensional array. I don't know the perl syntax to, say, push Birthday into the hash as element [0][0] of the weekday array, and the next time through the loop, push another event in as [0][1] or [1][0]. Similarly, I don't know the syntax to access same.
Using your variables, I'd write it like this:
push #{ $Weekdays{ $weekday }[ $kind eq 'Good' ? 0 : 1 ] }, $event;
However, I'd probably just make the Good/Bad specifiers keys as well. And given my druthers:
use autobox::Core;
( $Weekdays{ $weekday }{ $kind } ||= [] )->push( $event );
Note that the way I've written it here, neither expression cares whether or not an array exists before we start.
Is there some reason that
push #{ $Weekdays{Monday}[0] }, "whatever";
isn’t working for you?

Resources