Range operator [3..max?] for selecting elements from an array [duplicate] - powershell

How can I get the array element range of first to second last?
For example,
$array = 1,2,3,4,5
$array[0] - will give me the first (1)
$array[-2] - will give me the second last (4)
$array[0..2] - will give me first to third (1,2,3)
$array[0..-2] - I'm expecting to get first to second last (1,2,3,4) but I get 1,5,4 ???
I know I can do long hand and go for($x=0;$x -lt $array.count;$x++), but I was looking for the square bracket shortcut.

You just need to calculate the end index, like so:
$array[0..($array.length - 2)]
Do remember to check that you actually have more than two entries in your array first, otherwise you'll find yourself getting duplicates in the result.
An example of such a duplicate would be:
#(1)[0..-1]
Which, from an array of a single 1 gives the following output
1
1

There might be a situation where you are processing a list, but you don't know the length. Select-object has a -skiplast parameter.
(1,2,3,4,5 | select -skiplast 2)
1
2
3

As mentioned earlier the best solution here:
$array[0..($array.length - 2)]
The problem you met with $array[0..-2] can be explained with the nature of "0..-2" expression and the range operator ".." in PowerShell. If you try to evaluate just this part "0..-2" in PowerShell you will see that result will be an array of numbers from 0 to -2.
>> 0..-2
0
-1
-2
And when you're trying to do $array[0..-2] in PowerShell it's the same as if you would do $array[0,-1,-2]. That's why you get results as 1, 5, 4 instead of 1, 2, 3, 4.
It could be kind of counterintuitive at first especially if you have some Python or Ruby background, but you need to take it into account when using PowerShell.

Robert Westerlund answer is excellent.
This answer I just saw on the Everything you wanted to know about arrays page and wanted to try it out.
I like it because it seems to describe exactly what the goal is, end at one short of the upper bound.
$array[0..($array.GetUpperBound(0) - 1)]
1
2
3
4
I used this variation of your original attempt to uninstall all but the latest version from Get-InstalledModule. It's really short, but not perfect because if there are more than 9 items it still returns just 8, but you can put a larger negative number, though.
$array[-9..-2]
1
2
3
4

Related

How to access last argument in PowerShell script (args)

I have following code:
foreach ($arg in $args) {
Write-Host "Arg: $arg";
$param1=$args[0]
}
Write-host "Number of args: " $args.Length
write-host Last Arg is: "$($args.count)"
I get this, when I run it:
./print_last_arg.ps1 a b c
Arg: a
Arg: b
Arg: c
Number of args: 3
Last Arg is: 3
What I would like to have is name of last argument, so:
Last Arg is: 3
should be:
Last Arg is: c
Sorry for such a stupid question but I am totally begginer in PS and cannot google the result...
PowerShell supports negative indices to refer to elements from the end of a collection, starting with -1 to refer to the last element, -2 to the penultimate (second to last) one, and so on.
Therefore, use $args[-1] to refer to the last argument passed.
For more information, see the conceptual about_Arrays help topic.
Note that you can also use the results of expressions as indices; e.g., the equivalent of $args[-1] is $args[$args.Count-1] (assuming the array has at least one element).
Additionally, you may specify multiple indices to extract a sub-array of arbitrary elements. E.g., $args[0, -1] returns a (new) array comprising the input array's first and the last element (assuming the array has at least two elements).
.., the range operator is particularly useful for extracting a range of contiguous elements. E.g., $args[0..2] returns a (new) array comprising the first 3 elements (the elements with indices 0, 1, and 2).
You can even combine individual indices with ranges, courtesy of PowerShell's + operator performing (flat) array concatenation.
E.g., $args[0..2 + -1] extracts the first 3 elements as well as the last (assumes at least 4 elements).
Note: For syntactic reasons, if a single index comes first in the index expression, you need to make it an array with the unary form of , the array constructor operator, to make sure that + performs array concatention; e.g., $args[,-1 + 0..2] extracts the last element followed by the first 3.
Pitfall: Combining a positive .. start point with a negative end point for up-to-the-last-Nth-element logic does not work as intended:
Assume the following array:
$a = 'first', 'middle1', 'middle2', 'last'
It is tempting to use range expression 1..-2 to extract all elements "in the middle", i.e. starting with the 2nd and up to the penultimate element - but this does not work as expected:
# BROKEN attempt to extract 'middle1', 'middle2'
PS> $a[1..-2]
middle1
first
last
middle2
The reason is that 1..-2, as a purely arithmetic range expression, expanded to the following array (whose elements happen to be used as indices into another array): 1, 0, -1, -2. And it is these elements that were extracted: the 2nd, the first, the last, the penultimate.
To avoid this problem, you need to know the array's element count ahead of time, and use an expression to specify the end of the range as a positive number:
# OK: extract 'middle1', 'middle2'
# Note that the verbosity and the need to know $a's element count.
PS> $a[1..($a.Count-2)]
middle1
middle2
Unfortunately, this is both verbose and inconvenient, especially given that you may want to operate on a collection whose count you do not know in advance.
GitHub issue #7940 proposes a future enhancement to better support this use case with new syntax, analogous to C#'s indices-and-ranges feature, so that the above could be written more conveniently with syntax such as $a[1..^1]

How to put multiple where statements into function on kdb+

I'm trying to write a function using kdb+ which will look at the list, and find the values that simply meet two conditions.
Let's call the list DR (for data range). And I want a function that will combine these two conditions
"DR where (DR mod 7) in 2"
and
"DR where (DR.dd) in 1"
I'm able to apply them one at a time but I really need to combine them into one function. I was hoping I could do this
"DR was (DR.dd mod 7) in 2 and DR where (DR.dd) in 1"
but this obviously didn't work. Any advice?
You can utilize the and function to help with this, which is the same as &:
q)dr:.z.d+til 100
q)and
&
q)2=dr mod 7
10000001000000100000010000001000000100000010000001000000100000010000001000000..
q)1=dr.dd
00000000000000000000000001000000000000000000000000000000100000000000000000000..
q)(1=dr.dd)&2=dr mod 7
00000000000000000000000000000000000000000000000000000000100000000000000000000..
q)dr where(1=dr.dd)&2=dr mod 7
2021.02.01 2021.03.01
Its necessary wrap the first part in brackets due to how kdb reads code from right to left. This format changes slightly when doing this in a where clause, the brackets arent needed due to how each where clause is parsed, that is each clause between the commas are parsed seperately. However it is essentially doing the same thing as the code above.
q)t:([]date:dr)
q)select from t where 1=date.dd,2=date mod 7
date
----------
2021.02.01
2021.03.01
You could also do this using min to achieve similar results, like so:
DR where min(1=DR.dd;2=DR mod 7)

LIKE expression is not returning expected results. Issue or lack of understanding? (Probably the latter)

Using LIKE '%[0-9]%' to find "yellow 2 x 4 plate".
This is a simplified example that isn't working as I believe it should.
Table (command) with single column (commandtext, varchar).
Single entry in commandtext: yellow 2 x 4 plate.
SELECT
*
FROM command
WHERE commandtext LIKE '%[0-9]%'
Results = Empty set.
I expect that all this should be looking for is a digit between 0-9 surrounded by anythings else.
I am CLEARLY not getting something here...
As you have found out, you can use SQL standard SIMILAR TO:
... WHERE col SIMILAR TO '%[[:digit:]]%'
You could also use POSIX regular expressions:
... WHERE col ~ '[[:digit:]]'

Scalding: Create list from column in Pipe

I need to take a pipe that has a column of labels with associated values, and pivot that pipe so that there is a column for each label with the correct values in each column. So f example if I have this:
Id Label Value
1 Red 5
1 Blue 6
2 Red 7
2 Blue 8
3 Red 9
3 Blue 10
I need to turn it into this:
ID Red Blue
1 5 6
2 7 8
3 9 10
I know how to do this using the pivot command, but I have to explicitly know the values of the labels. How can I can dynamically read the labels from the “label” column into a list that I can then pass into the pivot command? I have tried to create list with:
pipe.groupBy('id) {_.toList('label) }
, but I get a type mismatch saying it found a symbol but is expecting (cascading.tuple.Fields, cascading.tuple.Fields). Also, from reading online, it sounds like using toList is frowned upon. The number of things in 'label is finite and not that big (30-50 items maybe), but may be different depending on what sample of data I am working with.
Any suggestions you have would be great. Thanks very much!
I think you're on the right track, you just need to map the desired values to Symbols:
val newHeaders = lines
.map(_.split(" "))
.map(a=>a(1))
.distinct
.map(f=>Symbol(f))
.toList
The Execution type will help you to combine with the subsequent pivot, for performance reasons.
Note that I'm using a TypedPipe for the lines variable.
If you want your code to be super-concise, you could combine lines 1 & 2, but it's just a stylistic choice:
map(_.split(" ")(1))
Try using Execution to get the list of values from the data. More info on executions: https://github.com/twitter/scalding/wiki/Calling-Scalding-from-inside-your-application

Adding zero in front of a number python

I am making program which will go through all possible choices.
Range is from 00000 to 99999.
For example:
00001,00002...01000,01001,01002...99999.
The problem is that i can make string as '00000' but as i convert it to int in order to add extra 1 to keep cycle going only one 0 appears. In that case i will get 0+1 = 1 and i need 00001.
Not completely sure how should i do it with lists because i might need it in the future for certain operations (to get one element from a current number 00450, 01004, 94571...)
Any advice/help would be greatly appreciated! :)
You can use zfill(num) on strings to add leading zeros
def convert_int(number,decimals) :
return str(number).zfill(decimals)
print convert_int(1,6) #prints 000001
I don't know if this is exactly what you want, but you can use string formatting. For example, this will turn int('00000') + 1 into '00001':
new_i = '%05d'%(int('00000')+1)
where %05d adds as many trailing zeros as necessary to whatever comes after % so the total length of the final string formatted number is 5.