I'm trying to change the number of items in array, over which a for loop is running, during the for loop, with the objective that this changes the number of loops. In a very simplified version, the code would look something like this:
var loopArray: [Int] = []
loopArray.append(1)
loopArray.append(2)
loopArray.append(3)
loopArray.append(4)
loopArray.append(5)
for x in 0..<Int(loopArray.count) {
print(x)
if x == 4 {
loopArray.append(6)
}
}
When running this code, 5 numbers are printed, and while the number 6 is added to the Array, the loopArray.count does not seem to update. How can I make the .count dynamic?
This is a very simplified example, in the project I'm working on, appending numbers to the array depends on conditions that may or may not be met.
I have looked for examples online, but have not been able to find any similar cases. Any help or guidance is much appreciated.
sfung3 gives the correct way to do what you want, but I think there needs to be a bit of explanation as to why your solution doesn't work
The line
for x in 0..<Int(loopArray.count)
only evaluates loopArray.count once, the first time it is hit. This is because of the way for works. Conceptually a for loop iterates through the elements of a sequence. The syntax is something like
for x in s
where
s is a sequence, give it type S
x is a let constant (you can also make it a var but that is not relevant to the current discussion) with type S.Element
So the bit after the in is a sequence - any sequence. There's nothing special about the use of ..< here, it's just a convenient way to construct a sequence of consecutive integers. In fact, it constructs a Range (btw, you don't need the cast to Int, Array.count is already an Int).
The range is only constructed when you first hit the loop and it's effectively a constant because Range is a value type.
If you don't want to use Joakim's answer, you could create your own reference type (class) that conforms to Sequence and whose elements are Int and update the upper bound each time through the loop, but that seems like a lot of work to avoid a while loop.
you can use a while loop instead of a for loop.
var i = 0
while i < loopArray.count {
print(i)
if i == 4 {
loopArray.append(6)
}
i += 1
}
which prints
0 1 2 3 4 5
var word = "morning"
var arr = Array(word)
for s in 0...word.count {
print(arr[s])
}
This will not print. Of course, if I substitute a number for s, the code works fine.
Why will it not accept a variable in the array access braces? Is this peculiar to Swift?
I've spent a long time trying to figure this out, and it's nothing to do with s being optional.
Anyone understand this?
you are using inclusive range ... instead of ..<, so s goes from 0 to 7, not 0 to 6.
However, in arr the index goes from 0 to 6 because there are 7 characters.
Thus, when the program tries to access arr[7], it throws an index out of range error.
If you were coding on Xcode, the debugger would have told you that there is no arr[7].
As for the code, here is a better way to print every item in arr than using an index counter:
var word = "morning"
var arr = Array(word)
for s in arr {
print(s)
}
This is called a "foreach loop", for each item in arr, it assigns it to s, performs the code in the loop, and moves on to the next item, assigns it to s, and so on.
When you have to access every element in an array or a collection, foreach loop is generally considered to be a more elegant way to do so, unless you need to store the index of a certain item during the loop, in which case the only option is the range-based for loop (which you are using).
Happy coding!
When I run it, it prints the array then throws the error Fatal error: Index out of range. To fix this, change the for loop to:
for s in 0..<word.count {
print(arr[s])
}
try this
when you use a word to recognize
size of Array your Array index start as 0 so array last index must be equal with your (word.count - 1)
var word = "morning"
var arr = Array(word)
for s in 0...(word.count-1) {
print(arr[s])
}
Basically avoid index based for loops as much as possible.
To print each character of a string simply use
var word = "morning"
for s in word { // in Swift 3 word.characters
print(s)
}
To solve the index issue you have to use the half-open range operator ..< since indexes are zero-based.
I have various subroutines that give me arrays of arrays. I have tested them separately and somehow when i write my main routine, I fail to make the program recognize my arrays. I know it's a problem of dereferencing, or at least i suspect it heavily.
The code is a bit long but I'll try to explain it:
my #leaderboard=#arrarraa; #an array of arrays
my $parentmass=$spect[$#spect]; #scalar
while (scalar #leaderboard>0) {
for my $i(0..(scalar #leaderboard-1)) {
my $curref=$leaderboard[$i]; #the program says here that there is an uninitialized value. But I start with a list of 18 elements.
my #currentarray=#$curref; #then i try to dereference the array
my $w=sumaarray (#currentarray);
if ($w==$parentmass) {
if (defined $Leader[0]) {
my $sc1=score (#currentarray);
my $sc2=score (#Leader);
if ($sc1>$sc2) {
#Leader=#currentarray;
}
}
else {#Leader=#currentarray;}
}
elsif ($w>$parentmass) {splice #leaderboard,$i,1;} #here i delete the element if it doesn't work. I hope it's done correctly.
}
my $leadref= cut (#leaderboard); #here i take the first 10 scores of the AoAs
#leaderboard = #$leadref;
my $leaderef=expand (#leaderboard); #then i expand the AoAs by one term
#leaderboard= #$leaderef; #and i should end with a completely different list to work with in the while loop
}
So I don't know how to dereference the AoAs correctly. The output of the program says:
"Use of uninitialized value $curref in concatenation (.) or string at C:\Algorithms\22cyclic\cyclospectrumsub.pl line 183.
Can't use an undefined value as an ARRAY reference at C:\Algorithms\22cyclic\cyclospectrumsub.pl line 184."
I would appreciate enormously any insight or recommendation.
The problem is with the splice that modifies the list while it is being processed. By using the 0..(scalar #leaderboard-1) you set up the range of elements to process at the beginning, but when some elements are removed by the splice, the list ends up shorter than that and once $i runs off the end of the modified list you get undefined references.
A quick fix would be to use
for (my $i = 0; $i < #leaderboard; $i++)
although that's neither very idiomatic nor efficient.
Note that doing something like $i < #leaderboard or #leaderboard-1 already provides scalar context for the array variable, so you don't need the scalar() call, it does nothing here.
I'd probably use something like
my #result;
while(my $elem = shift #leaderboard) {
...
if ($w==$parentmass) {
# do more stuff
push #result, $elem;
}
}
So instead of deleting from the original list, all elements would be taken off the original and only the successful (by whatever criterion) ones included in the result.
There seem to be two things going on here
You're removing all arrays from #leaderboard whose sumaarray is greater than $parentmass
You're putting in #Leader the array with the highest score of all the arrays in #leaderboard whose sumaarray is equal to $parentmass
I'm unclear whether that's correct. You don't seem to handle the case where sumaarray is less than $parentmass at all. But that can be written very simply by using grep together with the max_by function from the List::UtilsBy module
use List::UtilsBy 'max_by';
my $parentmass = $spect[-1];
my #leaderboard = grep { sumaarray(#$_) <= $parentmass } #arrarraa;
my $leader = max_by { score(#$_) }
grep { sumaarray(#$_) == $parentmass }
#leaderboard;
I'm sure this could be made a lot neater if I understood the intention of your algorithm; especially how those elements with a sumarray of less that $parentmass
Updated Question; Original below.
I am trying to create an array which represents a grid of cells, which have tuples containing the walls they are surrounded by.
I have come up with this:
rooms(Array) ->
Size = array:size(Array),
if
Size == ?HSIZE * ?VSIZE ->
Array;
true ->
HFactor = Size rem ?VSIZE,
VFactor = Size div ?HSIZE,
Room = {1+HFactor+11*VFactor,
7+HFactor+11*VFactor,
12+HFactor+11*VFactor,
6+HFactor+11*VFactor},
rooms(array:set(Size, Room, Array))
end.
When I run this with rooms(array:new()). I get the following array back:
{array,25,100,undefined,
{{{1,7,12,6},
{2,8,13,7},
{3,9,14,8},
{4,10,15,9},
{5,11,16,10},
{12,18,23,17},
{13,19,24,18},
{14,20,25,19},
{15,21,26,20},
{16,22,27,21}},
{{23,29,34,28},
{24,30,35,29},
{25,31,36,30},
{26,32,37,31},
{27,33,38,32},
{34,40,45,39},
{35,41,46,40},
{36,42,47,41},
{37,43,48,42},
{38,44,49,43}},
{{45,51,56,50},
{46,52,57,51},
{47,53,58,52},
{48,54,59,53},
{49,55,60,54},
undefined,undefined,undefined,undefined,undefined},
10,10,10,10,10,10,10,10}}
Which is quite close to the desired result, but there are two things I can't quite put my finger on (The numbers are correct). Why does it look like it is split up into multiple subarrays? What are those undefineds and 10's doing there? These are mostly due to my lack of erlang knowledge, because array:get produces the expected results, but I couldn't find anything which explains where they come from.
Original Question
rooms(Array) ->
Size = array:size(Array),
if
Size == 5 ->
Array;
Size rem 5 == 0 ->
rooms(array:set(Size, array:new(), Array));
true ->
In_Array = array:get(array:size(Array), Array),
In_Size = array:size(In_Array),
Room = {1+In_Size+11*In_Size,
7+In_Size+11*In_Size,
12+In_Size+11*In_Size,
6+In_Size+11*In_Size},
New_In = array:set(In_Size, Room, In_Array),
rooms(array:set(Size, New_In, Array))
end.
I call it with rooms(array:new()). but the result is
** exception error: bad argument
in function array:size/1 (array.erl, line 317)
in call from framework_kamer:rooms/1 (framework_kamer.erl, line 195)
Which makes sense because In_Array is not an array, but undefined. However, I can't figure out why.
Side question, is there an easier/cleaner/better way to do this?
You are (in the second call of the recursion) trying
In_Array = array:get(array:size(Array), Array),
As array is zero-indexed this will always fail, as the access will be always be off by one. Change this line to
In_Array = array:get(array:size(Array) - 1, Array),
and you are fine.
A few comments on your code:
Conventional variable naming in Erlang would be CamelCase without underscores (i.e. InArray)
Expressing a 2-dimensional array as nested arrays is almost never a good idea. Linearalise it by writing simple wrappers that recalculate a one-dimensional index from x and y as index = y * max_x + x.
I have a dozens of arrays with different array names and I would like to do some mathematical calculations in to for loop array by array. I srucked in calling these array into for loop. Is there anybody can help me with this problem? text1 array contains array names. My "s" struct has all these arrays with the same name content of text1 array.
text1=['s.CustomerArray.DistanceDriven','s.CustomerArray.TimeDriven'];
for i=1:3
parameter=str2num(text1(i));
k=size(parameter,2);
a=100;
y=zeros(a,k);
end
After this part my some other calculations should start using "parameter"
Regards,
Eren
I think you are doing several things wrong, here are some pointers.
Rather than listing them manually, consider looping over the fieldnames which can be obtained automatically.
If you are looping over strings, make sure to use a cell array with , rather than a matrix.
If you have a constant, declare it outside the loop, rather than inside the loop. This won't break the code but just makes for obsolete evaluations.
If you want to store results obtained inside a loop, make sure to add an index to the variable that you loop over.
That being said, here is a guess at what you are trying to do:
f = fieldnames(s.CustomerArray);
y = cell(numel(f),1);
parameter = NaN(numel(f),1);
for t = 1:numel(f)
parameter(t) = s.CustomerArray.(f{t});
y{t} = zeros(100,numel(f{t}));
end