How to just get key only on GNU Smalltalk? - smalltalk

I am currently using sortedCollection that stores dictionary of character (key) and number of occurrence for that character (value). When iterating through sortedCollection, how do I access the key value only?
e.g.
[que last notNil] whileTrue: [
stdout << 'current character is ' *key* << ' and occurs << *val* << ' times.' << nl.
]
Where que is the sortedCollection that sorts dictionary by value.
My goal is following: let's say que has:
[$a:20, $e:100] where first letter is the key of dictionary and second number is the value of dictionary. My output should look something like this:
current character is a and occurs 20 times.
current character is e and occurs 100 times.
I am not sure how to get a, or the key in dictionary since keys are arbitrary.

Assuming that que is a sorted collection and each element is an Association with the character as the key and the count as the value, as in your [$a:20, $e:100] example, you could do it like this:
que do: [:each | stdout << 'current character is ' << each key
<< ' and occurs ' << each value << ' times.' << nl]
If que is a Dictionary, use que keysAndValuesDo: [:char :count | stdout << "..." char << "..." count << "..." nl].
Depending on your overall application, you could also use a Bag, which is an unordered collection of elements that can appear multiple times (as opposed to a Set, which contains each element only once).
characters := 'hello world' asBag.
characters asSet do: [:each |
stdout << 'current character is ' << each
<< ' and occurs ' << (characters occurrencesOf: each)
<< ' times.' << nl]
You could also have a look at the #sortedByCount method and see whether it suits your case. I cannot tell from the reference how exactly its returned collection is structured, so I will not provide you with guessed example code.

Related

How do you detect blank lines in Fortran?

Given an input that looks like the following:
123
456
789
42
23
1337
3117
I want to iterate over this file in whitespace-separated chunks in Fortran (any version is fine). For example, let's say I wanted to take the average of each chunk (e.g. mean(123, 456, 789) then mean(42, 23, 1337) then mean(31337)).
I've tried iterating through the file normally (e.g. READ), reading in each line as a string and then converting to an int and doing whatever math I want to do on each chunk. The trouble here is that Fortran "helpfully" ignores blank lines in my text file - so when I try and compare against the empty string to check for the blank line, I never actually get a .True. on that comparison.
I feel like I'm missing something basic here, since this is a typical functionality in every other modern language, I'd be surprised if Fortran didn't somehow have it.
If you're using so-called "list-directed" input (format = '*'), Fortran does special handling to spaces, commas, and blank lines.
To your point, there's a feature which is using the BLANK keyword with read
read(iunit,'(i10)',blank="ZERO",err=1,end=2) array
You can set:
blank="ZERO" will return a valid zero value if a blank is found;
blank="NULL" is the default behavior that skips blank/returns an error depending on the input format.
If all your input values are positive, you could use blank="ZERO" and then use the location of zero values to process your data.
EDIT as #vladimir-f has correctly pointed out, you not only have blanks in between lines, but also after the end of the numbers in most lines, so this strategy will not work.
You can instead load everything into an array, and process it afterwards:
program array_with_blanks
integer :: ierr,num,iunit
integer, allocatable :: array(:)
open(newunit=iunit,file='stackoverflow',form='formatted',iostat=ierr)
allocate(array(0))
do
read(iunit,'(i10)',iostat=ierr) num
if (is_iostat_end(ierr)) then
exit
else
array = [array,num]
endif
end do
close(iunit)
print *, array
end program
Just read each line as a character (but note Francescalus's comment on the format). Then read the character as an internal file.
program stuff
implicit none
integer io, n, value, sum
character (len=1000) line
n = 0
sum = 0
io = 0
open( 42, file="stuff.txt" )
do while( io == 0 )
read( 42, "( a )", iostat = io ) line
if ( io /= 0 .or. line == "" ) then
if ( n > 0 ) print *, ( sum + 0.0 ) / n
n = 0
sum = 0
else
read( line, * ) value
n = n + 1
sum = sum + value
end if
end do
close( 42 )
end program stuff
456.000000
467.333344
3117.00000

How do I need to change the datatype in a textfile in order to read a String and not a Integer (C++/CLI, OleDb)?

My goal is it to read from a text file. This text file contains different columns and rows for each value. I can read the file as long as I don't change the datatype that windows set on its own. But I do not want the "plz" and "nr" column to be numbers (integers) but a text (String) value because a plz could contain values like "01979" and the nr could contain something like "4a". As a number the starting zero would be lost and this way something like a postcard would never reach its intended destination.
This way I need to change the datatype in a "schema.ini" file. But it doesn't work. I think I make some mistakes and do not follow the tutorial the way I need to do: "Schema.ini File"
Everytime I tried to read a String I got an Exception because it still want to read an Int32-values that I would need to convert into a string.
I did name the file "kunde.txt"
knr|nachname|vorname|plz|ort|strasse|nr
1|Müller|Johan|12345|Muster|Musterstr|1
2|Kummer|Freude|23456|Feeling|Gefühlswelt|4a
Col 0 = knr, 1 = nachname, 2 = vorname, 3 = plz, 4 = ort, 5 = strasse, 6 = nr
con->ConnectionString =
"Provider=Microsoft.JET.OLEDB.4.0;" +
"Data Source=D:/C++/Quellen;" +
"Extended Properties=text";
// ....
meineKunden->CommandText =
"SELECT knr, nachname, vorname, plz, ort, strasse, nr " +
"FROM kunde.txt ";
// ....
String ^ str;
while(reader->Read()){
str += Convert::ToString(reader->GetInt32(0));
str += " ";
str += reader->GetString(3);
str += " ";
str += reader->GetString(6);
str += "\r\n";
}
this->txb_Insert->Text = str;
My schema.ini
[kunde.txt]
ColNameHeader=True
Format=Delimited(|)
3=plz Char Width 5
6=nr Char Width 10
I did try with "Col3" instead of "3". I did use "Text" rather tan "Char", and I did even attempted it without Width. But everytime I got the same failure message. Even if i use 4 or 7 ... since I am not sure how it will be counted in the ini / txt file.
Exception:
System.InvalidCastException: Die angegebene Umwandlung ist ungültig.
bei System.Data.OleDb.ColumnBinding.ValueString()
bei System.Data.OleDb.OleDbDataReader.GetString(Int32 ordinal)
The exception is calls already by str += reader->GetString(3)
If I am correct column 3 contains plz, this way.
Could someone please say what I do understand wrong with the schema.ini file?
Since I could read the file without mistakes as long as I doesn't try to specific change the datatype in some columns the problems need to be with the ini file. At least I think so.
EDIT: I did change my ini-file to:
[kunde.txt]
ColNameHeader=True
Format=Delimited(|)
Col1="knr" Integer
Col2="nachname" Text
Col3="vorname" Text
Col4="plz" Text
Col5="ort" Text
Col6="strasse" Text
Col7="nr" Text
Now it works for "plz" but the exception is called in the last row, when I call the "nr". WTF?
You have to maintain that the way you read data from the file suits the way it's written in .
So if the file in not written by you and you have to use it,try to know if it has a specific structure (for ex: fixed length record delimited fields , fixed length record fixed length fields.. etc) and use a way that suits this structure to read it.
Also try to know how fields of records are written in details because the way you read is the same as you write .

Explain why storing the value of printf in a variable and then printing it gives an extra value?

int d;
d=printf("\n%d%d%d%d",1,2,3,4);
printf("%d",d);
The code gives the output as 1,2,3,4,5.
I don't understand why an integer greater than the last one is being printed.
printf returns the total number of characters written. In the first printf call that is 4 digits from the 4 variables and the newline character which adds up to 5. So the return value is 5 which is what you get in the second call.

How to load 2D array from a text(csv) file into Octave?

Consider the following text(csv) file:
1, Some text
2, More text
3, Text with comma, more text
How to load the data into a 2D array in Octave? The number can go into the first column, and all text to the right of the first comma (including other commas) goes into the second text column.
If necessary, I can replace the first comma with a different delimiter character.
AFAIK you cannot put stings of different size into an array. You need to create a so called cell array.
A possible way to read the data from your question stored in a file Test.txt into a cell array is
t1 = textread("Test.txt", "%s", "delimiter", "\n");
for i = 1:length(t1)
j = findstr(t1{i}, ",")(1);
T{i,1} = t1{i}(1:j - 1);
T{i,2} = strtrim(t1{i}(j + 1:end));
end
Now
T{3,1} gives you 3 and
T{3,2} gives you Text with comma, more text.
After many long hours of searching and debugging, here's how I got it to work on Octave 3.2.4. Using | as the delimiter (instead of comma).
The data file now looks like:
1|Some text
2|More text
3|Text with comma, more text
Here's how to call it: data = load_data('data/data_file.csv', NUMBER_OF_LINES);
Limitation: You need to know how many lines you want to get. If you want to get all, then you will need to write a function to count the number of lines in the file in order to initialize the cell_array. It's all very clunky and primitive. So much for "high level languages like Octave".
Note: After the unpleasant exercise of getting this to work, it seems that Octave is not very useful unless you enjoy wasting your time writing code to do the simplest things. Better choices seems to be R, Python, or C#/Java with a Machine Learning or Matrix library.
function all_messages = load_data(filename, NUMBER_OF_LINES)
fid = fopen(filename, "r");
all_messages = cell (NUMBER_OF_LINES, 2 );
counter = 1;
line = fgetl(fid);
while line != -1
separator_index = index(line, '|');
all_messages {counter, 1} = substr(line, 1, separator_index - 1); % Up to the separator
all_messages {counter, 2} = substr(line, separator_index + 1, length(line) - separator_index); % After the separator
counter++;
line = fgetl(fid);
endwhile
fprintf("Processed %i lines.\n", counter -1);
fclose(fid);
end

How do I use Perl to parse the output of the sqlplus command?

I have an SQL file which will give me an output like below:
10|1
10|2
10|3
11|2
11|4
.
.
.
I am using this in a Perl script like below:
my #tmp_cycledef = `sqlplus -s $connstr \#DLCycleState.sql`;
after this above statement, since #tmp_cycledef has all the output of the SQL query,
I want to show the output as:
10 1,2,3
11 2,4
How could I do this using Perl?
EDIT:
I am using the following code:
foreach my $row (#tmp_cycledef)
{
chomp $row;
my ($cycle_code,$cycle_month)= split /\s*\|\s*/, $row;
print "$cycle_code, $cycle_month\n";
$hash{$cycle_code}{$cycle_month}=1
}
foreach my $num ( sort keys %hash )
{
my $h = $hash{$num};
print join(',',sort keys %$h),"\n";
}
the fist print statement prints:
2, 1
2, 10
2, 11
2, 12
3, 1
3, 10
3, 11
but the out is always
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
Well, this one is actually how you might do it in perl:
# two must-have pragmas for perl development
use strict;
use warnings;
Perl allows for variables to be created as they are used, $feldman = some_function() means that you now have the variable $feldman in your local namespace. But the bad part about this is that you can type $fldman and take a long time finding out why what you thought was $feldman has no value. Turning on strictures means that your code fails to compile if it encounters an undeclared variable. You declare a variable with a my or our statement (or in older Perl code a use vars statement.
Turning on warnings just warns you when you're not getting values you expect. Often warnings tends to be too touchy, but they are generally a good thing to develop code with.
my %hash; # the base object for the data
Here, I've declared a hash variable that I creatively called %hash. The sigil (pronounced "sijil") "%" tells that it is a map of name-value pairs. This my statement declared the variable and makes it legal for the compiler. The compiler will warn me about any use of %hsh.
The next item is a foreach loop (which can be abbreviated "for"). The loop will process the list of lines in #tmp_cycledef assigning each one in turn to $row. ( my $row).
We chomp the line first, removing the end-of-line character for that platform.
We split the line on the '|' character, creating a list of strings that had been separated by a pipe.
And then we store it in a two-layered hash. Since we want to group them by at least the first number. We could do this by array, and create an array at the location in the hash like so: push #{$hash{$key}}, $val, but I typically want to collapse duplicates (not that there were any duplicates in your sample.)
Here:
foreach my $row ( #tmp_cycledef ) {
chomp $row; # removes the end-of-line character when present.
my ( $key, $val ) = split /\|/, $row;
# One of the best ways to merge lists is a presence-of idea
# with the hash holding whether the value is present
$hash{$key}{$val} = 1;
}
Once we have the data in the structure, we need to iterate both level of hash keys. You wanted to separate the "top level" numbers by lines, but you wanted the second numbers concatenated on the same line. So we print a line for each of the first numbers and join the list of strings stored for each number on the same line, delimited by commas. We also sort the list: { $a <=> $b } just takes to keys and numerically compares them. So you get a numeric order.
# If they were alpha keys our sort routine, we would just likely say sort keys %hash
foreach my $num ( sort { $a <=> $b } keys %hash ) {
my $h = $hash{$num};
print "$num ", join( ',', sort { $a <=> $b } keys %$h ), "\n";
}
As I said in the comments, sort, by default, sorts in character order so you can just say sort keys %hash.
To help you out, you really need to read some of these:
strictures
warnings
perldata
perlfunc -- especially my, foreach, chomp, split, keys, sort and join
And the data structure tutorial
Use a hash of arrays to collect all the values for a single key together, then print them out:
init hash
for each line:
parse into key|value
append value to hash[key]
for each key in hash: # you can sort it, if needed
print out key, list of values
If your input is sorted (as it is in the provided sample), you don't actually need to bother with the hash of arrays/hashes. The code is a bit longer, but doesn't require you to understand references and should run faster for large datasets:
#!/usr/bin/perl
use strict;
use warnings;
my #tmp_cycledef = <DATA>;
my $last_key;
my #values;
for (#tmp_cycledef) {
chomp;
my ($key, $val) = split '\|';
# Seed $last_key with the first key value on the first pass
$last_key = $key unless defined $last_key;
# The key has changed, so it's time to print out the values associated
# with the previous key, then reset everything for the new one
if ($key != $last_key) {
print "$last_key " . join(',', #values) . "\n";
$last_key = $key;
#values = ();
}
# Add the current value to the list of values for this key
push #values, $val;
}
# Don't forget to print out the final key when you're done!
print "$last_key " . join(',', #values) . "\n";
__DATA__
10|1
10|2
10|3
11|2
11|4