I have a TDictionary and add some items to it:
for index := 0 to 10 do
dict.Add(IntToStr(index), index);
Now, I need to iterate the container and remove items I wanted:
pairEnum := dict.GetEnumerator;
while pairEnum.MoveNext do
begin
if pairEnum.Current.Value mod 2 = 0 then
dict.Remove(pairEunm.Current.Key);
end;
I expect I now only have odd number in the dictionary. But what I actually got are:
key=1 value=1
key=3 value=3
key=5 value=5
key=7 value=7
key=9 value=9
key=8 value=8 <-
Why the "8" wasn't removed from dictionary?
If I add more items. e.g.
for index := 0 to 12 do
dict.Add(IntToStr(index), index);
Then, the result is correct. Why is that? How can I correctly iterate a TDictionary and remove items? Thanks.
It is unsafe to remove items while iterating an enumerable. You should keep another list of the keys that you want to remove and start removing them once your iteration is completed.
You need to iterate through the dictionary in reverse. Unfortunately, Delphi by default does not provide a "For MyObj in dict Reverse" or similar function so you have to do this another way:
for ix := dict.Count - 1 downto 0 do
if (dict.Keys.ToArray[ix] mod 2) = 0 then
dict.Remove(dict.Keys.ToArray[ix]);
Related
I have a seemingly simple issue with my understanding of map types in Go. If I create a simple map such as
var thisMap = map[string]string {
"8f14e45fceea167a5a36dedd4bea2543": "Charming",
"1679091c5a880faf6fb5e6087eb1b2dc": "Citi",
"e4da3b7fbbce2345d7772b0674a318d5": "Chase",
}
Populate the keys into an array
keys := make([]string, len(supportedCards))
for k := range supportedCards {
keys = append(keys, k)
}
Then try to join these keys into a comma separated value that I can append to any string
fmt.Println(strings.Join(keys,","))
I expect the result to be
8f14e45fceea167a5a36dedd4bea2543,1679091c5a880faf6fb5e6087eb1b2dc,e4da3b7fbbce2345d7772b0674a318d5
But what I really see is
,,,8f14e45fceea167a5a36dedd4bea2543,1679091c5a880faf6fb5e6087eb1b2dc,e4da3b7fbbce2345d7772b0674a318d5
Why does iterating through the map create 6 entries instead of just 3?
https://play.golang.org/p/Ou67K1Kfvsf
With
keys := make([]string, len(supportedCards))
you create a []string with three empty elements. You can assign them using their indicies.
When you append it later, new entries are added at the end, producing your result with a length of 6, where the first three are empty.
In addition to #xarantolus's answer, instead of using indices you can keep your for-range loop unchanged by:
keys := make([]string, 0, len(supportedCards))
The third argument is capacity of the slide. Ref: https://tour.golang.org/moretypes/13
I need to construct a matrix; a number of columns and rows are also in the first row of the matrix, I'll make an example so its more clearer.
4 3
1 2 3
5 6 7
9 10 8
1 11 13
Where m=4 (number of rows) and n=3 (number of columns)
This is an example of a text file. Is something like this even possible?
Program Feb;
const
max=100;
type
Matrix=array[1..max,1..max] of integer;
var datoteka:text;
m,n:integer;
counter:integer;
begin
assign(datoteka,'datoteka.txt');
reset(datoteka);
while not eoln(datoteka) do
begin
read(datoteka, m);
read(datoteka, n);
end;
repeat
read eoln(n)
until eof(datoteka)
write (m,n);
end.
My code isn't a big help, cause I don't know how to write it.
First, have a look at the code I wrote to do the task, and then look at my explanation below.
program Matrixtest;
uses
sysutils;
var
NoOfCols,
NoOfRows : Integer;
Source : TextFile;
Matrix : array of array of integer;
FileName : String;
Row,
Col : Integer; // for-loop iterators to access a single cell of the matrix
Value : Integer;
begin
// First, construct the name of the file defining the matrix
// This assumes that the file is in the same folder as this app
FileName := ExtractFilePath(ParamStr(0)) + 'MatrixDef.Txt';
writeln(FileName); // echo it back to the screen so we can see it
// Next, open the file
Assign(Source, FileName);
Reset(Source);
read(Source, NoOfRows, NoOfCols);
writeln('Cols: ', NoOfCols, 'Rows: ', NoOfRows);
SetLength(Matrix, NoOfCols, NoOfRows);
readln(source); // move to next line in file
// Next, read the array data
for Row := 1 to NoOfRows do begin
for Col := 1 to NoOfCols do begin
read(Source, Value);
Matrix[Col - 1, Row - 1] := Value;
end;
end;
// Display the array contents
for Row := 1 to NoOfRows do begin
for Col := 1 to NoOfCols do begin
writeln('Row: ', Row, ' contents', Matrix[Col - 1, Row - 1]);
end;
end;
Close(Source); // We're done with the file, so close it to release OS resources
readln; // this waits until you press a key, so you can read what's been displayed
end.
In your program, you can use a two-dimensional array to represent your matrix. Free Pascal supports multi-dimensional arrays; see https://wiki.lazarus.freepascal.org/Multidimensional_arrays for more information.
This is a complex task, so it helps to know how to do more basic things like reading an array of a size known at compile-time from a text file.
The wrinkle in this task is that you are supposed to read the dimensions (numbers of rows and columns) of the matrix at run-time from the file which contains the matrix's contents.
One inefficient way to do this would be to declare the matrix array with huge dimensions, larger than anything you would expect in practice, using the type of array declaration in the Wiki page linked above.
A better way is to use dynamic arrays, whose dimensions you can set at run-time. To use this, you need to know:
How to declare a dynamic array in Free Pascal
How to set the dimensions of the array at run-time, once you've picked them up from your matrix-definition file (hint: SetLength is the way to do this)
The fact that a Free Pascal dynamic array is zero-based
The easiest way of managing zero-based arrays is to write your code (in terms of Row and Column variables) as if the matrix were declared as array[1..NoOfRows, 1..NoOfColumns] and subtract one from the array indexes only when you actually access the array, as in:
Row := 3;
Column := 4;
Value := Matrix[Row - 1, Column - 1];
I am using the list data type (http://www.aerospike.com/docs/guide/cdt-list.html
) in aerospike using a golang client. I can use the ListInsertOp (https://godoc.org/github.com/aerospike/aerospike-client-go#ListInsertOp) to insert values in the list of a given entry.
However, I want to update/delete a given list value using the ListSetOp (https://godoc.org/github.com/aerospike/aerospike-client-go#ListSetOp) or the ListRemoveOp (https://godoc.org/github.com/aerospike/aerospike-client-go#ListRemoveOp)
In order to do this, I need an index. How can I get this index ? Is there a way I can iterate through all the list values and get the index and then perform the update or delete operation ?
Assuming that you have the list called List.
Let us say you want to replace element called value with newItem
You can do that like:
...
for index, item := range List {
if item == value {
List[index] = newItem
}
}
...
In the above snippet, index is the index at which element item is present. By this way you can also replace element present on the particular index in the list with value.
Sample example in playground: https://play.golang.org/p/qOmsY9fbL2
As usual, items in the list are indexed by their integer position starting from zero.
Aerospike also supports negative indexing to start backwards from end of list.
Lists documentation in the Aerospike:
Elements are ordered by integer position.
Lists documentation in the Aerospike's Node.js client:
List operations support negative indexing. If the index is negative, the resolved index starts backwards from end of list.
Index/Range examples:
Index 0: First item in list.
Index 4: Fifth item in list.
Index -1: Last item in list.
Index -3: Third to last item in list.
Also mentioned in Go client source.
list := []string{“a”, “b”, “c”, “d”, “e”}
bin := aerospike.NewBin("listbin", list)
err := client.PutBins(nil, key, bin)
// to replace “d”:
op := aerospike.ListSetOp(bin.Name, 3, "replaced")
_, err = client.Operate(nil, key, op)
In an xquery expression, I have obtained a set of values within a for-expression, and one value is in a separate variable.
Now, I want to subtract the single value from first value of the list, and then subtract consecutive members of the list from each other-- and in the resulting set of difference values, I want to obtain the min/max values...
The query upto now looks like this--
let $value1:= 1998
let $rows_citations:=
$doc//div[#id="patent_citations"]
/div[#id="patent_citations_v"]
/table[#class="rel_patent"]
/tbody/tr[1]
/following-sibling::tr
for $pos in $rows_citations/position()
let $date2_c := customfn:dateconverter1($rows_citations[$pos]/td[3])
Now the subtraction I want is between first value of date2_c and value 1, and after that between consecutive members of date2_c... And from the resulting list I want the min/max values... How do I go about doing this?
I am esp. confused about creating a new list variable that stores all the differences, esp. when we are already inside a for loop, and are iterating over each value of a list (via variable date2_c)
I. This XQuery 3.0 query (which is also a pure XPath 3.0 expression):
let $pVal := 1,
$vList := (2,4,7,11,16),
$vList2 := ($pVal, subsequence($vList, 1, count($vList)-1)),
$vSubtactedList :=
map-pairs(function($m as xs:integer, $n as xs:integer) as xs:integer
{
$m - $n
},
$vList,
$vList2
)
return
(min($vSubtactedList), max($vSubtactedList))
produces the wanted result the minimum and maximum values from the list of subtractions:
1 5
II. XQuery 1.0 solution:
let $pVal := 1,
$vList := (2,4,7,11,16),
$vList2 := ($pVal, subsequence($vList, 1, count($vList)-1)),
$vSubtactedList :=
for $i in 1 to count($vList)
return
$vList[$i] - $vList2[$i]
return
(min($vSubtactedList), max($vSubtactedList))
This again produces the same correct result:
1 5
I declared my multidimentional array like this:
Dim invoice_discountitems(100, 1) As String
I Fill my array with this:
'Fill Array with items discounts
For i As Int16 = 0 To data_set.Tables("discount_items").Rows.Count - 1
invoice_discountitems(i, 0) = data_set.Tables("discount_items").Rows(i).Item("item_code")
invoice_discountitems(i, 1) = data_set.Tables("discount_items").Rows(i).Item("discountitem_average")
Next
Now how i can remove the filled items of this array?
Thanks in Advance
Because an array is statically sized, an empty array is the same as a freshly initialized array. So, if you want to clear the whole thing:
invoice_discountitems = New String(100, 1)
Or, if you wish to clear specific elements, use Array.Clear()
Array.Clear(invoice_discountitems, 1, 10)