Stylus multiple loop iterators - stylus

Is it possible to implement something like this in Stylus?
for $i in 1..5 and $n in a b c d e
.icon-{$i}:before{
content: $n
}

To answer your question: yes.
and here is how: http://codepen.io/anon/pen/jIbdq
icon_contents = ( "a" "b" "c" "d" "e" )
for v, k in icon_contents
.icon-{k+1}:before
content v

Related

Perl remove same value back to back with splice

I am trying to remove, the same values twice in an array, it is located back to back, this is my code
#{$tmp_h->{'a'}} = qw/A B B C/;
print Dumper ($tmp_h);
my $j = 0;
foreach my $cur (#{$tmp_h->{'a'}}) {
if ($cur eq 'B') {
splice(#{$tmp_h->{'a'}}, $j, 1);
}
$j++;
}
print Dumper $tmp_h;
However what got is,
$VAR1 = {
'a' => [
'A',
'B',
'B',
'C'
]
};
$VAR1 = {
'a' => [
'A',
'B',
'C'
]
};
I am expecting both 'B' to be removed in this case, what could possibly went wrong?
That code is removing from an array while iterating over it, pulling the carpet from underneath itself; is that necessary?
Instead, iterate and put elements on another array if the adjacent ones aren't equal. So iterate over the index, looking up an element and the next (or previous) one.†
I presume that B is just an example while in fact it can be any value, equal to its adjacent one.
It's interesting that regex can help too, with its simple way to find repeated patterns using backreferences
my #ary = qw(a b b c d d e f f f g);
my $str_ary = join '', #ary;
$str_ary =~ s/(.)\g{-1}//g;
my #new_ary = split //, $str_ary;
say "#new_ary"; #--> a c e f g
This removes pairs of adjacent values, so if there is an odd number of equal adjacent values it leaves the odd one (f above). As a curiosity note that it can be written in one statement
my #new_ary = split //, join('', #ary) =~ s/(.)\g{-1}//gr;
The join-ed array, forming a string, is bound to the substitution operator where /r modifier is crucial, for allowing this and returning the changed string which is then split back into a list.
To change an array in place have it assign to itself.‡
But single-letter elements are only an example, likely. With multiple characters in elements we can't join them by empty string because we wouldn't know how to split that back into an array; we have to join by something that can't be in any one element, clearly a tricky proposition. A reasonable take is a line-feed, as one can expect to know whether elements are/not multiline strings
my #ary = qw(aa no no way bah bah bah go);
my $str_ary = join "\n", #ary ;
$str_ary =~ s/([^\n]+)\n\g{-1}//g;
my #new = grep { $_ } split /\n/, $str_ary;
say "#new"; #--> aa way bah go
This would still have edge cases with interesting elements, like spaces and empty strings (but then any approach would).
† For example
use warnings;
use strict;
use feature 'say';
my #ary = qw(a b b c d d e f f f g);
my #new_ary;
my $i = 0;
while (++$i <= $#ary) {
if ($ary[$i] ne $ary[$i-1]) {
push #new_ary, $ary[$i-1]
}
else { ++$i }
}
push #new_ary, $ary[-1] if $ary[-1] ne $ary[-2];
say "#new_ary"; #--> a c e f g
‡ Done for the arrayref in the question
#{ $hr->{a} } = qw/A B B C/;
#{$hr->{a}} = split //, join('', #{$hr->{a}}) =~ s/(.)\g{-1}//gr;
say "#{$hr->{a}}"; #--> A C
The Perl documentation tells you in perlsyn under Foreach Loops:
If any part of LIST is an array, foreach will get very confused if you
add or remove elements within the loop body, for example with splice. So
don't do that.
You can iterate over the indices instead, but don't forget to not increment the index when removing a value:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my $tmp_h = {a => [qw[ A B B C ]]};
print Dumper($tmp_h);
my $j = 0;
while ($j <= $#{ $tmp_h->{a} }) {
my $cur = $tmp_h->{a}[$j];
if ($cur eq 'B') {
splice #{ $tmp_h->{a} }, $j, 1;
} else {
++$j;
}
}
print Dumper($tmp_h);
Or start from the right so you don't have to worry:
my $j = $#{ $tmp_h->{a} };
while ($j-- >= 0) {
my $cur = $tmp_h->{a}[$j];
splice #{ $tmp_h->{a} }, $j, 1 if $cur eq 'B';
}
But the most straight forward way is to use grep:
#{ $tmp_h->{a} } = grep $_ ne 'B', #{ $tmp_h->{a} };

Delete array elements ksh

I need to delete specific values in an array (which vary in their index positions), similar to the splice function in javascript.
Example:
set -A ARRAY1 "a" "b" "c" "d" "e"
set -A ARRAY2 "a" "c" "e"
# Expected ARRAY1 after splice: "b" "d"
What I've tried:
I iterated through the arrays to find matches to the values I want deleted, and set them to empty ("").
ITERATION=0
for i in "${ARRAY1[#]}"
do
for j in "${ARRAY2[#]}"
do
if [[ $i == $j ]]
then
ARRAY1[$ITERATION]=""
fi
done
ITERATION=$((ITERATION+1))
done
#ARRAY1 after emptying values: "" "b" "" "d" ""
After that, I made a variable to store the concatenation of the first array's values.
VARIABLE=${ARRAY1[#]}
Then set the array back together again.
set -A ARRAY1 $VARIABLE
# VARIABLE: b d
Now the ARRAY1 has 2 indexes with values "b" and "d" as expected.
echo "ARRAY1: ${ARRAY1[#]}"
# output: ARRAY1: b d
I tried searching for the correct way to do this but couldn't find anything, and I think my solution is not right, even if it seems to work. Is there a correct or better way to do this? Is there a function for this in ksh?
Thanks in advance!
So, what you want to do is take the difference of sets. An indexed array is not a good representation of a set. However, the keys of an associative array is.
Try this:
array1=( "a" "b" "c" "d" "e" )
array2=( "a" "c" "e" )
# declare an associative array
typeset -A tmp
# populate it
for elem in "${array1[#]}"; do
tmp[$elem]=1
done
# remove elements
for elem in "${array2[#]}"; do
unset "tmp[$elem]"
done
# reassign the array with the keys of the assoc. array
array1=( "${!tmp[#]}" )
printf "%s\n" "${array1[#]}"
b
d
Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.
Using the same notation as the OP, just need one small change to the if/then block to unset the array position:
ITERATION=0
for i in "${ARRAY1[#]}"
do
for j in "${ARRAY2[#]}"
do
if [[ $i == $j ]]
then
unset ARRAY1[$ITERATION]
fi
done
ITERATION=$((ITERATION+1))
done
Here's a ksh fiddle of the above.
A quick dump of the current array:
echo "ARRAY1: ${ARRAY1[#]}"
ARRAY1: b d

Array lowercase

I'm new to Perl and I've ran into a little problem. I'm trying to pick one value out of an array to make it lowercase.
E.g.
my #letters = qw(A B C D E F F A S D F E S F);
Now I want to pick the letter F and make it lowercase, how can I go about doing this?
Keep in mind my array is very large and it should be able to take any changes made by the user.
Thanks in advance.
for my $c (#letters) {$c = lc($c) if $c eq"F"}
I absolutely don't know what you mean by pick and make it.
This is my approach:
my #letters = qw(A B C D E F F A S D F E S F);
#letters = map { tr/F/f/; $_ } #letters;
UPDATE: as #TLP commented, this is a simpler way:
my #letters = qw(A B C D E F F A S D F E S F);
tr/F/f/ for #letters;
Unless you want to keep the orginal list
tr/F/f/ for #letters
Short inplace modification is
my #letters = qw(A B C D E F F A S D F E S F);
map {s/(F)/\l$1/;} #letters;
print "#letters";
Output:
A B C D E f f A S D f E S f
If you already know the location in the array, you would do: $array[5] = lc($array[5]). If you don't there are several ways. One of them uses C style looping:
for (my $i=0; $i < #array; $i++) {
$array[$i] = lc($array[$i]) if $array[$i] eq 'F';
}
another is map:
map {$_ = lc if $_ eq 'F'} #array;

Move element in perl array

I have an element in an array that I'd like to move accordingly.
#array = ("a","b","d","e","f","c");
Basically I'd like to find the index of "c" and then place it before "d" again based on "d"'s index. I'm using these characters as an example. It has nothing to do with sorting alphabetically.
Try doing this using array slice and List::MoreUtils to find array elements indexes :
use strict; use warnings;
use feature qw/say/;
# help to find an array index by value
use List::MoreUtils qw(firstidx);
my #array = qw/a b d e f c/;
# finding "c" index
my $c_index = firstidx { $_ eq "c" } #array;
# finding "d" index
my $d_index = firstidx { $_ eq "d" } #array;
# thanks ysth for this
--$d_index if $c_index < $d_index;
# thanks to Perleone for splice()
splice( #array, $d_index, 0, splice( #array, $c_index, 1 ) );
say join ", ", #array;
See splice()
OUTPUT
a, b, c, d, e, f
my #array = qw/a b d e f c/;
my $c_index = 5;
my $d_index = 2;
# change d_index to what it will be after c is removed
--$d_index if $c_index < $d_index;
splice(#array, $d_index, 0, splice(#array, $c_index, 1));
Well, here's my shot at it :-)
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw/ first /;
my #array = ("a","b","d","e","f","c");
my $find_c = 'c';
my $find_d = 'd';
my $idx_c = first {$array[$_] eq $find_c} 0 .. $#array;
splice #array, $idx_c, 1;
my $idx_d = first {$array[$_] eq $find_d} 0 .. $#array;
splice #array, $idx_d, 0, $find_c;
print "#array";
This prints
C:\Old_Data\perlp>perl t33.pl
a b c d e f
Another solution using array slices. This assumes you know the desired of the elements in the array.
use strict;
use warnings;
my #array = qw(a b d e f c);
print #array;
my #new_order = (0, 1, 5, 2, 3, 4);
my #new_list = #array[#new_order];
print "\n";
print #new_list;
See this link to PerlMonks for details.
You can use splice to insert an element at a specific index in an array. And a simple for loop to find the indexes you seek:
my #a = qw(a b d e f c);
my $index;
for my $i (keys #a) {
if ($a[$i] eq 'c') {
$index = $i;
last;
}
}
if (defined $index) {
for my $i (keys #a) {
if ($a[$i] eq 'd') {
splice #a, $i, 1, $a[$index];
}
}
}
use Data::Dumper;
print Dumper \#a;
Output:
$VAR1 = [
'a',
'b',
'c',
'e',
'f',
'c'
];
Note that this code does not remove the c element. To do that you need to keep track of whether you insert the c before or after d, since you are changing the indexes of the array.
U can try this
my $search = "element";
my %index;
#index{#array} = (0..$#array);
my $index = $index{$search};
print $index, "\n";

perl generating array based on the input pattern

Here is my program
#!/usr/bin/perl -w
use strict;
use warnings;
my $pattern = 'a .. f';
I am looking for a way to get an array from this pattern. The one way which I thought is to use split this in to three and get the array as follows. But it seems that this is not a feasible solution as in future pattern will change. It may be something like 'a..f1..9' so the split may not work there OR I have to write more generalize code for it.
So looking for a way to generate the array based on the input pattern provided.
Maybe the Parse::Range module can help you.
Try this, capture the anchor characters via regex:
my $pattern = 'a .. f';
my #ar;
if($pattern =~ /([a-f])\s*\.\.\s*([a-f])/) {
#ar = ($1..$2);
}
This needs input validation because it will probably break fairly easily on invalid patterns, but it fits your basic spec:
#!/usr/bin/env perl
use strict;
use warnings;
my $pattern = 'a .. f';
print join(' ', make_arr($pattern)), "\n";
$pattern = 'a..f1..9';
print join(' ', make_arr($pattern)), "\n";
sub make_arr {
my $pat = shift;
my #arr;
while ($pat =~ s/(\w)\s*\.\.\s*(\w)//) {
push #arr, $1 .. $2;
}
return #arr;
}
Output:
a b c d e f
a b c d e f 1 2 3 4 5 6 7 8 9
single line regex double eval:
$pattern =~ s/(\w)\s*\.\.\s*(\w)/"\"\#{['$1'..'$2']} \""/gee;
result:
a b c d e f
This will even work on:
my $pattern = 'a .. f1 .. 8';
result:
a b c d e f 1 2 3 4 5 6 7 8
To convert this string to a list is left to the reader :)
Regards
rbo
You coud use eval and change a bit your pattern :
#!/usr/bin/perl
use strict;
use warnings;
use 5.10.1;
use Data::Dumper;
my $pattern = '"a" .. "f", 2 .. 4';
my #array = eval $pattern;
if ($#) {
say "eval failed: $#";
} else {
say Dumper \#array;
}
output:
$VAR1 = [
'a',
'b',
'c',
'd',
'e',
'f',
2,
3,
4
];
Do you realise that perl supports that sort of syntax already? i.e., 1..5 gives you the array (1,2,3,4,5). a..f gives you the array (a,b,c,d,e,f).
print join (", ", a..f), "\n" # a, b, c, d, e, f
print join (", ", a..f, 1..3), "\n" # a, b, c, d, e, f, 1, 2, 3
Actually this is basically what M42 is suggesting but he's not explicitly pointing out that perl supports syntax not unlike that. He's turning the string into the array using the eval.

Resources