Converting TArray<string> to string (Delphi 10.2 Tokyo) - arrays

I want to convert a TArray<string> which is second parameter of third SelectDirectory (out Directories parameter) function to string to write selected path to edit box.
But I don't allow the user for multiple selection. So, only one directory can be selected.
What should I do?

Although you mention only the special case with a one-element-array, a general approach to convert a TArray<string> into a single string with all the array elements separated by a given string is using string.Join:
const
sep = ',';
var
arr: TArray<string>;
S: string;
begin
S := string.Join(sep, arr);
end;

If SelectDirectory() returns True, the output array is guaranteed to have at least 1 element in it. Since you don't enable multiple selection, the array is guaranteed to have only 1 element in it. So just access that element by index:
var
dirs: TArray<string>;
if SelectDirectory('', dirs) then
Edit1.Text := dirs[0]; // <--

Related

How to show elements of array?

I have a small problem. I created a large array.
It looks like this:
var Array = [
["text10", "text11", ["text01", "text02"]],
["text20", "text21", ["text11", "text12"]]
]
If we write this way: Array[0] that shows all the elements.
If we write this way: Array[0][0] that shows "text1".
If we write this way: Array[0][2] that shows
-2 elements
-- 0: "text01"
-- 1: "text02"
.
If we write this way: Array[0][2].count or Array[0][2][0] it will not work
How do I choose each item, I need these elements for the tableView
The problem basically is that your inner array is illegal. Swift arrays must consist of elements of a single type. You have two types of element, String and Array Of String. Swift tries to compensate but the result is that double indexing can’t work, not least because there is no way to know whether a particular element will have a String or an Array in it.
The solution is to rearchitect completely. If your array entries all consist of the same pattern String plus String plus Array of String, then the pattern tells you what to do; that should be a custom struct, not an array at all.
as #matt already answered but I want to add this thing
Why Array[0][2].count or Array[0][2][0] not work
If you Define array
var array = [
["text10", "text11", ["text01", "text02"]],
["text20", "text21", ["text11", "text12"]]
]
And when you type array you can see it's type is [[Any]] However it contains String as well as Array
So When you try to get Array[0][2] Swift does not know that your array at position 2 has another array which can have count
EDIT
What you are asking now is Array of dictionary I suggest you to go with model i.e create struct or class and use it instead of dictionary
Now If you want to create dictionary then
var arrOfDict = ["text10" : ["text01", "text02"] , "text11" : ["text11", "text12"]]
And you can access with key name let arrayatZero = arrOfDict["text10"] as? [String]

Ada constant array of string literals

I have a large array in C that I wish to move into my ada project. That array is used to store filenames for assets which will later be loaded. It looks something like:
const char *filenames[NUMBER_OF_FILES] = {
/* file[0] */ "res/0.file",
/* ... */
/* file[n] */ "res/some_more/complicated/file.name"
};
I want to move this into an ada package body, but can't find a decent way to do it. Obviously my first attempt was:
filenames : constant array (File_Index) of String := (
index_0 => "res/0.file",
-- ...
index_n => "res/some_more/complicated/file.name"
);
But of course String is an unconstrained type, so Ada won't allow that. I switched it to use Unbounded_Strings, which worked, but was very ugly (having to wrap each string with To_Unbounded_String.
Is there any way to make an array of unconstrained types whose size will be known at compile time like this, or do I have to use unbounded strings?
It’s a bit low-level and repetitive, but perhaps you can create a little program (maybe even in Ada!) to generate something like
with Ada.Text_IO; use Ada.Text_IO;
procedure Lambdabeta is
F1 : aliased constant String := "res/0.file";
F2 : aliased constant String := "res/some_more/complicated/file.name";
type Strings is array (Positive range <>) of access constant String;
Filenames : constant Strings := (F1'Access,
F2'Access);
begin
for J in Filenames'Range loop
Put_Line (Filenames (J).all);
end loop;
end Lambdabeta;
See also this answer on minimising the pain of using To_Unbounded_String.
Arrays can't contain objects of indefinite types.
Basically you have two options:
Use another container than an array.
Encapsulate the strings in a definite type.
So you could use Ada.Containers.Indefinite_Vectors instead of an array:
with Ada.Containers.Indefinite_Vectors;
package Settings is
------------------------------------------------------------------
-- You may want to put this block in a separate package:
package String_Vectors is
new Ada.Containers.Indefinite_Vectors (Index_Type => Positive,
Element_Type => String);
function "+" (Left, Right : String) return String_Vectors.Vector
renames String_Vectors."&";
function "+" (Left : String_Vectors.Vector;
Right : String) return String_Vectors.Vector
renames String_Vectors."&";
------------------------------------------------------------------
File_Names : constant String_Vectors.Vector :=
"/some/file/name" +
"/var/spool/mail/mine" +
"/etc/passwd";
end Settings;
So you could use Ada.Strings.Unbounded.Unbounded_String instead of String:
with Ada.Strings.Unbounded;
package Settings_V2 is
function "+" (Item : in String) return Ada.Strings.Unbounded.Unbounded_String
renames Ada.Strings.Unbounded.To_Unbounded_String;
type String_Array is array (Positive range <>)
of Ada.Strings.Unbounded.Unbounded_String;
File_Names : constant String_Array :=
(+"/some/file/name",
+"/var/spool/mail/mine",
+"/etc/passwd");
end Settings_V2;
What has not yet been mentioned is that you can just use a function:
subtype File_Index is Integer range 1 .. 3;
function Filename (Index : File_Index) return String is
begin
case Index is
when 1 => return "res/0.file";
when 2 => return "res/1.file";
when 3 => return "res/some_more/complicated/file.name";
end case;
end Filename;
Using Filename (1) in your code is identical to accessing an array element.

How to make array values all capital letters lazarus

The user inputs string values into a string array via an InputBox, once the values are stored, how do I make all the letters become capital letters only, such as the example below. These values must then basically overwrite the non-capitalized values within the array so that they can be displayed within a listbox later. I know that i need to use the UpperCase function but i can't seem to get it to work correctly as it appears non-capitalized again.
This is my first time experimenting with arrays and the UpperCase function so please be nice.
Example : 'Hockey', 'Tennis', 'Football'
to 'HOCKEY', 'TENNIS', 'FOOTBALL'
UpperCase Code:
procedure TFrm2016Assignment9.BtnCapitalStrClick(Sender: TObject);
var
Capitalise : string;
begin
Capitalise := UpperCase(nBasicsStrArray[0]);
end;
Display Code:
procedure TFrm2016Assignment9.BtnDisplayStrClick(Sender: TObject);
begin
dDateTime := Date() + Time();
LstOutput.Items.Add('String Array : ' + DateTimeToStr(dDateTime));
LstOutput.Items.Add(nBasicsStrArray[0]);
LstOutput.Items.Add(nBasicsStrArray[1]);
LstOutput.Items.Add(nBasicsStrArray[2]);
LstOutput.Items.Add(nBasicsStrArray[3]);
LstOutput.Items.Add(nBasicsStrArray[4]);
LstOutput.Items.Add('****');
end;
UpperCase is a function that returns a new value with letters made upper case. It does not modify its argument. You assigned this new value to a local variable and immediately forgot it.
Remove the BtnCapitalStrClick method that serves no purpose. When you add the strings convert them to upper case:
LstOutput.Items.Add(UpperCase(nBasicsStrArray[0]));
Since this is a Lazarus topic it should be noted that the UpperCase solution is only correct for the first 128 ASCII characters. Lazarus uses UTF8 encoding by default, and therefore fhe function UTF8Uppercase (in unit LazUTF8) is a more general solution because it considers all characters.
What data type is nBasicsStrArray?
Just use UpperCase on the whole string:
whatever := UpperCase(someEdit.text);

How to split a string of only ten characters e.g."12345*45688" into an array

I'm making a simple calculator where you type values into an edit box. I need to split the string into a number of arrays depending on how many *+-/ there are in the sum for instance
I have 22+22*22-22/22 I want to break that into five different arrays because there are five different groups of numbers. Then later I am going to add array1 to array two multiply that by array3 and subtract that by array4 and divide that by array 5.
If you want to read something like that, especially if you want to evaluate mathematical expressions, you need more than just an array-splitter; you need a real parser. Doing it right requires a bit of compiler theory. I'd recommend you take a look at Let's Build A Compiler, a tutorial that covers everything you'll need to know about expression parsing (and a bit more, since he's actually building a simple compiler) and makes it easy to understand. All examples are in Turbo Pascal, so it should be easy for a Delphi coder to read.
Delphi XE has a SplitString function that does exactly what you need.
If you wish to get the result of that equation, you should try a non-visual component, called CalcExpress. It's free and you can get it from here:
CalcExpress
Download link is at the end of the page text
Here's a function which may help you on the way.
It breaks down an input string into an array of sub-strings, based upon a provided set of pre-defined character sets.
It will give you an array of strings, which will be ["22", "+", "22", "*", "22", "-", "22", "/", "22"].
From there on you'll have to identify the numbers and the operators, and you'll have to group and execute the calculations according to the rules for operator precedence.
TCharSet = Set of Char;
TStringArray = Array of String;
function GetSubStrings(InputString: String; CharacterSets: Array of TCharSet): TStringArray;
// Get Sub-strings
var
Index: Integer;
Character: Char;
SubString: String;
SubStringArray: TStringArray;
CharacterSetIndex: Integer;
PreviousCharacterSetIndex: Integer;
begin
// Get
SubString := '';
SetLength(SubStringArray, 0);
PreviousCharacterSetIndex := -1;
for Index := 1 to Length(InputString) do
begin
// Character
Character := InputString[Index];
// Character Set Index
CharacterSetIndex := GetCharacterSet(Character, CharacterSets);
// Add
if (CharacterSetIndex = PreviousCharacterSetIndex) or (Index = 1) then
// Add Character to SubString
SubString := SubString + Character
else
begin
// Add SubString To SubString Array
SetLength(SubStringArray, Length(SubStringArray) + 1);
SubStringArray[Length(SubStringArray) - 1] := SubString;
// New SubString
SubString := Character;
end;
// Previous Character Set Index
PreviousCharacterSetIndex := CharacterSetIndex;
// Add last SubString
if Index = Length(InputString) then
begin
// Add SubString To SubString Array
SetLength(SubStringArray, Length(SubStringArray) + 1);
SubStringArray[Length(SubStringArray) - 1] := SubString;
end;
end;
// Result
Result := SubStringArray;
end;
function GetCharacterSet(Character: Char; CharacterSets: Array of TCharSet): Integer;
// Get Character Set
var
Index: Integer;
CharacterSet: TCharSet;
begin
// Get
Result := -1;
for Index := 0 to Length(CharacterSets) - 1 do
begin
// Character Set
CharacterSet := CharacterSets[Index];
// Check
if Character in CharacterSet then
begin
// Result
Result := Index;
// Break
Break;
end;
end;
end;

Array begin from 0 or 1 in Delphi 5.0 Pascal?

I want to do an ArrayList in Delphi 5.0. So I found a solution doing this code:
var arr: array of String;
OK, but every time I add something I do this:
var
Form1: TForm1;
var arr : array of String;
procedure TForm1.Button1Click(Sender: TObject);
var aux :string;
var len:integer;
begin
len := Length(arr) + 1;
SetLength(arr, len);
arr[len-1] := 'abc' + IntToStr(len);
Button1.Caption := arr[len-1]; // just to writeout something
end;
I'm a C++ programmer, and I do not know anything about Pascal. I always heard a Pascal index begins from 1, not 0. As in the above procedure I do arr[len-1] because of 0 index begin.
Is there a better way than Pascal arrays? Like with C++'s std::vector?
Dynamic arrays' indexes begin with zero
var
a: array of Integer;
begin
SetLength(a, 500);
a[0] := 0;
Static arrays can have arbitrary indexes
var
i: Integer;
b: array [50..100] of Integer;
c: array[-10..10] of Integer;
begin
for i := 50 to 100 do b[i] := i * i;
// Note negative starting index above in declaration
for i := -10 to 10 do c[i] := i * i;
Strings' indexes begin with one
var
c: String;
begin
c := 'Zap!';
c[1] := 'W';
ShowMessage(c); /// shows 'Wap!'
Anyway you can always use Low() and High() functions which return the lower and higher index of an array.
For handling a list of strings the most commonly used class is TStringList which is found in unit Classes.
What you're using is known as a dynamic array which is different from a Pascal classic array. Dynamic arrays are variable in size and the index is 0 based.
Classic Pascal arrays are not 0 nor 1 based... It's up to the programmer where the index start or ends. The only compiler restriction is that the index must be an ordinal type. You can declare
procedure x;
var
IntArr: array[50..75] of Integer;
StrArr: array[0..49] of string;
DblArr: array[1..10] of Double;
Delphi Pascal also has a nice feature that helps iterating through an array of any dimension:
Simply use for i:= Low(Array) to High(Array) do....
which is completely transparent to starting offset i.e. 0,1 or 5 or whatever.
I tried to edit the above answer to improve it but the editor keeps rejecting my posting. Arrays can have negative indexes.
var
A:array[-20..9] of integer;
B:array[-30..-10] of integer;
These are both the same, an array of 20 integers but will not be treated the same by the compiler because the index range is different. Allows you to make the data fit the problem domain, not the other way around.
Now, a string like var S:string[200]; is technically equivalent to var s:packed array[0..200] of char where byte 0 is the length except when you use a string with no length or the specified length is greater than 255, then the string is 1 to whatever current size it is. Because strings can be dynamic it's not good to depend on the 0th element to contain length.
When you use SetLength(array, length) it is worth mentioning that it has indexes starting from 0 as mentioned up to length-1. Also in pascal index on array can be character from ANSI table. So you can define array like a:array['A'..'Z'] of integer. This comes in handy when you need to count all characters in your Strings or Char Array.

Resources