Sadly I don't know the exact word for what my problem is, but I try to explain it and I'd be happy if someone could tell me what I should be looking for :)
I have two arrays
Array 1 with Name, Surname, and Array 2 with Name, Surname aswell.
Of course, Surnames and Names are NOT unique, but the combination of them is unique.
So now I'd need to check if the Combination of Array 1 IS existing in Array 2, if not do something...
Now my problem is that i know -contains but I don't know how to use that on multiple hashes (Contains Surname or Name only is not useful, it has to be and)
i tried the following
if ( $oldList -notcontains $newPerson.Name -and $newPerson.Surname) {....}
But it neither worked nor I expected it to work or I did another mistake?!
Could anybody give me some advice? Thanks in advance
PS. It is not Surname/Name in my case, but I for understanding Surname/Name is easier!
Update
The Hashtables (or Arrays?!) look with an Write-Host like this:
#{Name=Peter; Surname=Fox}.... and so on
Update 2 - Solution
Hey Guys, just for every future reader who maybe doesn't find out by himself...
It's an Compare-Object $arr1 $arr2 - and it outputs every diffenence by either => odr =<
:) Therefore question is answered (by myself :P)
Compare-Object $arr1 $arr2
delivers the solution I was looking for. It shows differences by => and <= and therefore you can evaluate if it is containd in arr2 or not.
Related
I'm a beginner to bash, and I'm quite struggling with associative array. I created many associative arrays and integrated all the data by using key '0, 1, 2, 3'. Simply saying ArrayA[0], ArrayB[0], ArrayC[0].... have data on a common topic. So these keys are important to me. Now I want to make another array to access these keys, and I want the keys of the new arrays to be the data of the related keys. For example,
declare -A NewArray
ArrayA[0]=3
ArrayB[0]=4
ArrayC[0]=6
NewArray[ArrayA[0]+ArrayB[0]+ArrayC[0]]=0
so that it could be NewArray[346]=0 or NewArray[3,4,6]=0. Any helps would be so much appreciated, I've been thinking about this for hours.
Bash has no concatenation operator as it doesn't need any.
NewArray[${ArrayA[0]}${ArrayB[0]}${ArrayC[0]}]=0
echo ${NewArray[346]}
or
NewArray[${ArrayA[0]},${ArrayB[0]},${ArrayC[0]}]=0
echo ${NewArray[3,4,6]}
I have a powershell script where I group and store a collection of Conputernames in a hashtable. Everithing works fine so far.
$table = #{}
$pcs = "w7cl002","w7cl002","w7cl001","w7cl002","w7cl008", `
"w7lp001","w7lp001","w7cl008","w7cl004","w7lp001"
foreach ($pc in $pcs){
if ($table.Keys -notcontains $pc){
$Table.Add($pc,1)
}
else{
$occ = $table.get_item($pc) +1
$table.set_item($pc,$occ)
}
}
$table
This is what I want and what I get.
Name Value
---- -----
stflw7lp001 3
stflw7cl002 3
stflw7cl004 1
stflw7cl001 1
stflw7cl008 2
Initially, I wanted to do this by using a 2D-Array. But after 5 hours struggling and running my head against a wall, I gave up and realized it with a hash table.
I just would be interested in whether this is possible using a 2D array?
2D arrays (in the C# sense, not the Java sense) are icky in PowerShell. I tend to avoid them. There is no direct language support for them either, and you have to create them with New-Object.
As for your code, you can achieve the same with this:
$pcs = "w7cl002","w7cl002","w7cl001","w7cl002","w7cl008",
"w7lp001","w7lp001","w7cl008","w7cl004","w7lp001"
$table = #{}
$pcs | Group-Object -NoElement | ForEach-Object { $table[$_.Name] = $_.Count }
No need for awkward loops and code that looks like an unholy combination of C# and VBScript (honestly, none of the actual working lines in your code look like PowerShell, except for the first three and the last).
If you need arrays of arrays instead of a hashtable, you can do so as well:
$result = $pcs | Group-Object -NoElement | ForEach-Object { ,($_.Name, $_.Count) }
However, you really don't want to work this way. For one, you can often get confused whether you have an array or a scalar as an item. Some operations may automatically unroll the array again, etc. IMHO it's much better to work with objects when you can. In this case, just use the result from Group-Object directly. It has handy Name and Count properties that spell out exactly what they are, instead of [0] and [1] which are a bit more opaque.
If you need nicer property names, just project into new objects:
$pcs | group -n | % {
New-Object PSObject -Property #{
PC = $_.Name
Count = $_.Count
}
}
or
$pcs | group -n | select #{l='PC';e={$_.Name}},Count
Generally, when using PowerShell, think of your data as objects and your problem as operations on those objects. Then try to find how to make those operations happen with things the language already gives you. Manipulation of collection classes, or C-like code with lots of loops almost always looks out of place and wrong in PowerShell – usually for good reason, because the pipeline is often a better, easier, and shorter way of accomplishing the same. I can probably count the number of times I used a for loop in PowerShell over the past few years on both hands, while I wouldn't need both hands to count the number of times I used a foreach loop. Those are rare things to use.
In general, what I end up with in a situation like this is not a 2D array, but an array of tuples, or an array of custom objects. This is what import-csv gives you by default. For my work, this is a good representation of a relation, and many of the transforms I want are some combination of set ops and relational ops.
BTW, I'm only a beginner in Powershell.
After reading this I wrote a naive attempt to produce this
col1
---------
1
4
7
from this
ARRAY[[1,2,3], [4,5,6], [7,8,9]]
This works
SELECT unnest((ARRAY[[1,2,3], [4,5,6], [7,8,9]])[1:3][1:1]);
But I in my case, I don't know the length of the outer array.
So is there a way to hack together the slice "string" to take into account this variability?
Here was my attempt. I know, it's a bit funny
_ids := _ids_2D[('1:' || array_length(_ids_2D, 1)::text)::int][1:1];
As you can see, I just want to create the effect of [1:n]. Obviously '1:3' ain't going to parse nicely into what the array slice needs.
I could obviously use something like the unnest_2d_1d Erwin mentions in the answer linked above, but hoping for something more elegant.
If you are trying to get the first element of all nested (2nd dimension) arrays inside an array (1st dimension) then you may use
array_upper(anyarray, 1)
to get all elements of a specific dimension
anyarray[1:array_upper(anyarray, 1)][<dimension num>:<dimension num>]
e.g, to get all elements of the first dimension
anyarray[1:array_upper(anyarray, 1)][1:1]
as in the code above. Please refer to PostgreSQL manual section on Arrays for more information.
I am attempting to take a file and store the items from the file into an associative array in bash. An associative array might not be the best course for my action, but from my research it appears to be a good fit. I have a file that looks like the following:
personid
phone
phone
phone
personid
phone
phone
phone
Please note, persionid is always 20 digits, and phone is always 10. There is nothing else in this file, and no whitespace, just one of these per line. I wanted to map these to an associative array with my key being personid and my value being phone.
The code I've worked on regarding this piece is the following:
declare -A person
while read key; do
if [ ${#key} -eq 20 ] ; then
personID="$key"
else
phone="$key"
fi
person=( ["$personID"]="$phone" )
done < myFile.txt
for i in "${!person[#]}"
do
echo "key: $i"
echo "value: ${person[$i]}"
done
It will correctly store and print one personID as the key and one phone as the value....but there should be multiple values for phone. I'm thinking when I assign person, I must be doing that wrong, or have it in the wrong placed. But I've played around with it for quite sometime now and can't get it right. Never used associative arrays before, so having a little trouble. Thanks in advance for the help!
Associative arrays are no different to any other arrays in that there will always be exactly a 1:1 mapping from key (or index) to value. In your case, you want a 1:many mapping from key (personID) to values (phone numbers). One way to do this would simply to store a list of phone numbers which is effectively the "single" value mapped to a personID. You can construct your list however you like, with whitespace, or comma delimiters or anything else.
For example if you want : as your delimiter, you could do this to add each phone number to the list:
if [ -n ${person[$personID]} ] ; then
person[$personID]}="${person[$personID]}:$phone"
else
person[$personID]}="$phone"
fi
I am new to Perl and having some difficulty with arrays in Perl. Can somebody will explain to me as to why I am not able to print the value of an array in the script below.
$sum=();
$min = 999;
$LogEntry = '';
foreach $item (1, 2, 3, 4, 5)
{
$min = $item if $min > $item;
if ($LogEntry eq '') {
push(#sum,"1"); }
print "debugging the IF condition\n";
}
print "Array is: $sum\n";
print "Min = $min\n";
The output I get is:
debugging the IF condition
debugging the IF condition
debugging the IF condition
debugging the IF condition
debugging the IF condition
Array is:
Min = 1
Shouldn't I get Array is: 1 1 1 1 1 (5 times).
Can somebody please help?
Thanks.
You need two things:
use strict;
use warnings;
at which point the bug in your code ($sum instead of #sum) should become obvious...
$sum is not the same variable as #sum.
In this case you would benefit from starting your script with:
use strict;
use warnings;
Strict forces you to declare all variables, and warnings gives warnings..
In the meantime, change the first line to:
#sum = ();
and the second-to-last line to:
print "Array is: " . join (', ', #sum) . "\n";
See join.
As others have noted, you need to understand the way Perl uses sigils ($, #, %) to denote data structures and the access of the data in them.
You are using a scalar sigil ($), which will simply try to access a scalar variable named $sum, that has nothing to do with a completely distinct array variable named #sum - and you obviously want the latter.
What confuses you is likely the fact that, once the array variable #sum exists, you can access individual values in the array using $sum[0] syntax, but here the sigil+braces ($[]) act as a "unified" syntactic constract.
The first thing you need to do (after using strict and warnings) is to read the following documentation on sigils in Perl (aside from good Perl book):
https://stackoverflow.com/a/2732643/119280 - brian d. foy's excellent summary
The rest of the answers to the same question
This SO answer
The best summary I can give you on the syntax of accessing data structures in Perl is (quoting from my older comment)
the sigil represents the amount of data from the data structure that you are retrieving ($ of 1 element, # for a list of elements, % for entire hash)
whereas the brace style represent what your data structure is (square for array, curly for hash).
As a special case, when there are NO braces, the sigil will represent BOTH the amount of data, as well as what the data structure is.
Please note that in your specific case, it's the last bullet point that matters. Since you're referring to the array as a whole, you won't have braces, and therefore the sigil will represent the data structure type - since it's an array, you must use the # sigil.
You push the values into the array #sum, then finish up by printing the scalar $sum. #sum and $sum are two completely independent variables. If you print "#sum\n" instead, you should get the output "11111".
print "Array is: $sum\n";
will print a non-existent scalar variable called $sum, not the array #sum and not the first item of the array.
If you 'use strict' it will flag the user of un-initialized variables like this.
You should definitly add use strict; and use warnings; to your script. That would have complained about the print "Array is: $sum\n"; line (among others).
And you initialize an array with my #sum=(); not with my $sum=();
Like CFL_Jeff mentions, you can't just do a quick print. Instead, do something like:
print "Array is ".join(', ',#array);
Still would like to add some details to this picture. )
See, Perl is well-known as a Very High Level Language. And this is not just because you can replace (1,2,3,4,5) with (1..5) and get the same result.
And not because you may leave your variables without (explicitly) assigning some initial values to them: my #arr is as good as my #arr = (), and my $scal (instead of my $scal = 'some filler value') may actually save you an hour or two one day. Perl is usually (with use warnings, yes) good at spotting undefined values in unusual places - but not so lucky with 'filler values'...
The true point of VHLL is that, in my opinion, you can express a solution in Perl code just like in any human language available (and some may be even less suitable for that case).
Don't believe me? Ok, check your code - or rather your set of tasks, for example.
Need to find the lowest element in a array? Or a sum of all values in array? List::Util module is to your command:
use List::Util qw( min sum );
my #array_of_values = (1..10);
my $min_value = min( #array_of_values );
my $sum_of_values = sum( #array_of_values );
say "In the beginning was... #array_of_values";
say "With lowest point at $min_value";
say "Collected they give $sum_of_values";
Need to construct an array from another array, filtering out unneeded values? grep is here to save the day:
#filtered_array = grep { $filter_condition } #source_array;
See the pattern? Don't try to code your solution into some machine-codish mumbo-jumbo. ) Find a solution in your own language, then just find means to translate THAT solution into Perl code instead. It's easier than you thought. )
Disclaimer: I do understand that reinventing the wheel may be good for learning why wheels are so useful at first place. ) But I do see how often wheels are reimplemented - becoming uglier and slower in process - in production code, just because people got used to this mode of thinking.