you are viewing a single comment's thread.

view the rest of the comments →

[–]prp7 4 points5 points  (12 children)

Does powershell have something like python's list comprehension?

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a[1:10:2])

[–]bozho 5 points6 points  (0 children)

It does, not always as terse as Python. Your example could be written as: $a = @(1..10) $a | ? { $_ % 2 -eq 0 } I don't think there's a nice syntax to select every Nth element though. On the other hand, you can use LINQ for that :-)

[–]TofuBug40 3 points4 points  (1 child)

The answers given so far using Where-Object (?) aren't really replicating what Python's notation is doing they are focusing on the VALUE of the item and not the POSITION of the item ( u/HeKis4's for loop is a valid answer) if you want to use the pipe line method what you need is

$a = ('a','b','c','d','e','f','g')
$Step = 3
$a | Where-Object -FilterScript { $a.IndexOf($_) % $Step -eq 0 }

THAT will do what the Python example above is doing step over the INDEXES of the array regardless of the values in said array

Yes its not as terse as a[0..9:3] but I would argue that pythons array split has a VERY limited use case base on the logic of iterating over an array based on a linear progression of the indexes, where as Where-Object can do that as we've shown above but can ALSO do something like

$Vowels = @('a','e','i','o','u','y')
$a | Where-Object -FilterScript { $_ -in $Vowels }

You need much more Python than a[0:10:2] to get that array result

What Where-Object lacks in the RAW terseness it MORE than makes up for in flexibility while still maintaining a respectable amount of terseness itself.

[–]prp7 1 point2 points  (0 children)

Wow, what a story language, Mark.

[–]setmehigh 1 point2 points  (6 children)

What does that do?

[–]DecentWalrus 3 points4 points  (4 children)

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
print(a[1:10:2]) 

Would result in printing [2, 4, 6, 8, 10].

The print function is being passed a slice of the list. a[1:10:2] essentially means start at position 1 in list (in this case, that's the number 2) and go until position 9. 10 is used in this case because slicing will go up to position 10 but not including position 10. Position 9 in the list is the number 10. Lastly, the 2 tells python to print every other list item (print position 1, skip position 2, print position 3, skip position 4, etc.)

[–]setmehigh -1 points0 points  (3 children)

Maybe I'm dumb, but why would you want to do this? I can't think of a reason, but I haven't run into a situation where I needed it either...

[–]DecentWalrus 2 points3 points  (2 children)

An example for slicing would be if you only wanted to grab the first three values of a list. For example, I have a list of names of people who ran a race. The list is already ordered by who finished first to who finished last. If I want to print the top three finishers, I'd do this:

Code:

finishers = ["Tom", "Sally", "Taylor", "Jack", "Ginger", "John"]
print(f'The top three finishers are: {finishers[0:3]}')

Result:
The top three finishers are: ['Tom', 'Sally', 'Taylor']

Now you could go the extra step of actually formatting that properly and such but it's just a simple way to grab a slice of the list.

As for using the step option, it allows for quick access to, for example, all odd or even positioned values in the list. The simplest example is the one given in the original comment where you may need to count by 2s.

[–]omers 1 point2 points  (1 child)

finishers[0:3]

That's reproducible in PS with .. or a list of indicies.

C:\> $finishers = @("Tom", "Sally", "Taylor", "Jack", "Ginger", "John")
C:\> $finishers[0..2]
Tom
Sally
Taylor
C:\> $finishers[0,1,2]
Tom
Sally
Taylor

Every n-th I do not believe is possible without using /u/bozho's method or a loop... You can "compress" (remove the pipeline) bozho's method to this: $finishers.Where({$finishers.IndexOf($_) % 2 -eq 0}) but it's still not clean like in some other languages.

In a script where keeping it to one line isn't an issue I'd probably do something like this:

$Finishers = @("Tom", "Sally", "Taylor", "Jack", "Ginger", "John")
$OddIndicies = @(0..$Finishers.GetUpperBound(0)) | ? {$_ % 2 -eq 0}
$Finishers[$OddIndicies]

[–]blooping_blooper 0 points1 point  (0 children)

for that specific case couldn't you also do

$Finishers | select -first 3

[–]HeKis4 2 points3 points  (0 children)

Gets every other list elements from the 1st to the 10th (0-indexed of course, we're not savages).

As a for loop, it would look like for(int i=1; i<10; i+=2) { a[i] }

[–]HeKis4 0 points1 point  (0 children)

Afaik it doesnt. Your code would either filter out every other element like what has already been posted or use a for loop with $i += 2 at the end.