I have the following code in which I am making a form where I want to enter multiple timesteps, lat, and longitude entriess as shown below:
my $mw = MainWindow->new;
my $exec_frame2 = $mw->Frame()->pack(-side => "top");
my $title_frame_track = $exec_frame2->Frame()->pack(-side=>"top");
$title_frame_track->Label(-text => '')->pack(-side => "top");
$title_frame_track->Label(-text => 'Storm Coordinates/Track')->pack(-side => "top");
my $frame1 = $exec_frame2->Frame()->pack(-side=>"top");
$frame1->Label(-text => 'Time Step:')->pack(-side=>"left");
my $timestep1 = $frame1->Entry(-width => 15)->pack(-side =>"left");
$frame1->Label(-text => 'Lat:')->pack(-side=>"left");
my $lat1 = $frame1->Entry(-width => 5)->pack(-side =>"left");
$frame1->Label(-text => 'Lon:')->pack(-side=>"left");
my $lon1 = $frame1->Entry(-width => 5)->pack(-side =>"left");
$frame1->Label(-text => 'Max Wind:')->pack(-side=>"left");
my $maxwind1 = $frame1->Entry(-width => 5)->pack(-side=>"left");
my $frame2 = $exec_frame2->Frame()->pack(-side=>"top");
$frame2->Label(-text => 'Time Step:')->pack(-side=>"left");
my $timestep2 = $frame2->Entry(-width => 15)->pack(-side =>"left");
$frame2->Label(-text => 'Lat:')->pack(-side=>"left");
my $lat2 = $frame2->Entry(-width => 5)->pack(-side =>"left");
$frame2->Label(-text => 'Lon:')->pack(-side=>"left");
my $lon2 = $frame2->Entry(-width => 5)->pack(-side =>"left");
$frame2->Label(-text => 'Max Wind:')->pack(-side=>"left");
my $maxwind2 = $frame2->Entry(-width => 5)->pack(-side=>"left");
my $frame3 = $exec_frame2->Frame()->pack(-side=>"top");
$frame3->Label(-text => 'Time Step:')->pack(-side=>"left");
my $timestep3 = $frame3->Entry(-width => 15)->pack(-side =>"left");
$frame3->Label(-text => 'Lat:')->pack(-side=>"left");
my $lat3 = $frame3->Entry(-width => 5)->pack(-side =>"left");
$frame3->Label(-text => 'Lon:')->pack(-side=>"left");
my $lon3 = $frame3->Entry(-width => 5)->pack(-side =>"left");
$frame3->Label(-text => 'Max Wind:')->pack(-side=>"left");
my $maxwind3 = $frame3->Entry(-width => 5)->pack(-side=>"left");
MainLoop ;
This code is supposed to create a image like this:
Is there a way to make put the variables frame, timestep, lat, lon and maxwind into arrays so that I can put the code above into a loop? I attempted to do condense the first set of code into a looop below but got an error.
for (i=0,i<10;i++)
{
$frame[$i] = $exec_frame2->Frame()->pack(-side=>"top");
$frame[$i]->Label(-text => 'Time Step:')->pack(-side=>"left")
$timestep[$i] = $frame[$i]->Entry(-width => 15)->pack(-side =>"left");
$frame[$i]->Label(-text => 'Lat:')->pack(-side=>"left");
my $lat[$i] = $frame[$i]->Entry(-width => 5)->pack(-side =>"left");
$frame[$i]->Label(-text => 'Lon:')->pack(-side=>"left");
my $lon[$i] = $frame[$i]->Entry(-width => 5)->pack(-side =>"left");
$frame[$i]->Label(-text => 'Max Wind:')->pack(-side=>"left");
my $maxwind[$i] = $frame[$i]->Entry(-width => 5)->pack(-side=>"left");
}
Is there anyway to tweak this code to get the desired result and keep the code more concise?
Scalar variables in Perl have to start with a dollar sign. Declaring a variable is also a good habit:
for (my $i = 0; $i < 10; ++$i) {
There's also a semicolon missing after the $timestep[$i] assignment. Moreover, my shouldn't be used for array elements, e.g.
my $lat[$i] = ... # Wrong!
Related
I am developing an application on React and I needed to add product checkboxes to the form. Everything works correctly except that the last action (marking or removing the checkbox) does not go to the server (the error is not in the server, I tested it separately). Here is the output of the checkboxes:
<Form.Group className="mb-3">
<Form.Label>Товары</Form.Label>
{prodsl.map((emp, index) =>
<div className="mb-3">
<Form.Check
type='checkbox'
value={emp.id}
name='pp'
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
{emp.name}
</div>
)}
</Form.Group>
And here is the handler (checkedState - an array of checkbox states):
const [prods, setProd] = useState([])
const [checkedState, setCheckedState] = useState(
new Array(555).fill(false)
);
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
let arr = []
const updatedProd = checkedState.map((item, index) => {
if (item) {
arr = [...arr, index]
}
}
);
setProd(arr);
};
Submit form handler:
const newOrder = async () => {
const response = await addOrder(prods, client, emp, d1, d2)
stat++;
}
I tried to do a separate check before sending, I tried to call the function before sending it to a random checkbox so that this change would be the last and would not be counted.
Set states in react are async. It means that your values are not updated immediately after your setstate.
In order to fix the issue, you have 2 options.
Use the updatedCheckedState variable to set your prod:
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
let arr = []
const updatedProd = updatedCheckedState.map((item, index) => {
if (item) {
arr = [...arr, index]
}
}
);
setProd(arr);
};
Move your logic into useEffect:
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
};
useEffect(() => {
let arr = []
const updatedProd = checkedState.map((item, index) => {
if (item) {
arr = [...arr, index]
}
});
setProd(arr);
}, [checkedState]);
And as a suggestion, use arr.push(index) instead of arr = [...arr, index];
This is part of a previous post: What's the React best practice for getting data that will be used for page render?
I'm adding objects to an array with useState([]). Each object has a firstName and a lastName value. I want to add up all of the length of all the first and last names to get a total character count so that I can then get the average name length for each.
What I have currently is giving me the wrong values: firstName (100) lastName (106)
The values should be 6 & 7
const [players, setPlayers] = useState([]);
const [firstNameCount, setFirstNameCount] = useState(0);
const [lastNameCount, setLastNameCount] = useState(0);
useEffect(() => {
setPlayers([]);
teams.forEach(teamId => {
axios.defaults.headers.common['Authorization'] = authKey;
axios.get(endPoints.roster + teamId)
.then((response) => {
let teamPlayers = response.data.teamPlayers;
console.log(response.data.teamPlayers)
setPlayers(prevPlayers => [...prevPlayers, ...teamPlayers]);
})
.catch((error) => {
console.log(error);
})
});
}, [teams]);
useEffect(() => {
players.forEach(player => {
setFirstNameCount(prevCount => prevCount + player.firstName.length);
setLastNameCount(prevCount => prevCount + player.lastName.length);
})
}, [players]);
If I change the code to this
useEffect(() => {
setPlayers([]);
teams.forEach(teamId => {
axios.defaults.headers.common['Authorization'] = authKey;
axios.get(endPoints.roster + teamId)
.then((response) => {
let teamPlayers = response.data.teamPlayers;
console.log(response.data.teamPlayers)
setPlayers(prevPlayers => [...prevPlayers, ...teamPlayers]);
teamPlayers.forEach(player => {
setFirstNameCount(prevCount => prevCount + player.firstName.length);
setLastNameCount(prevCount => prevCount + player.lastName.length);
})
})
.catch((error) => {
console.log(error);
})
});
}, [teams]);
It slows down the render considerably and I get: firstName (7), lastName (7), which is still wrong.
I'd recommend you move your team/player loading out of your component and into a store, separate from the component, but in any case, why put the lengths in state? Why not just compute it from the player state when you need it?
const sum = values => values.reduce((r, v) => r + v, 0);
const avg = values => sum(values) / values.length;
const avgFirst = avg(players.map(p => p.firstName.length));
const avgLast = avg(players.map(p => p.lastName.length));
I realize that this would cause it to be recomputed on every render, but unless your list of players is massive I would expect this to be reasonably performant.
Well instead of setting state for every increment what you could do is add up all the lengths of firstnames and lastnames and then set the state like this:
useEffect(() => {
setPlayers([]);
teams.forEach(teamId => {
axios.defaults.headers.common['Authorization'] = authKey;
axios.get(endPoints.roster + teamId)
.then((response) => {
let teamPlayers = response.data.teamPlayers;
console.log(response.data.teamPlayers)
setPlayers(prevPlayers => [...prevPlayers, ...teamPlayers]);
let firstNameCount = 0;
let lastNameCount = 0;
teamPlayers.forEach(player => {
firstNameCount += player.firstName.length;
lastNameCount += player.lastName.length;
})
setFirstNameCount(prevCount => prevCount + firstNameCount);
setLastNameCount(prevCount => prevCount + lastNameCount);
})
.catch((error) => {
console.log(error);
})
});
}, [teams]);
Let me know if it helps :)
I'm trying to do this in ReasonML without success.
The problem is that I don't know the object keys.
const items = {
foo: () => 'ok',
bar: () => 'ok2'
};
const result = Object.keys(items).reduce((acc, key) => ({
...acc, [key]: items[key]()
}), {});
console.log(result);
It is possible, but I don't see why List.fold_left should be a requirement. Js.Dict.map is much more appropriate:
let items = Js.Dict.fromList([
("foo", () => "ok"),
("bar", () => "ok2")
]);
let result = items |> Js.Dict.map([#bs] f => f());
I am trying to delete my archive in Amazon Glacier. I'm doing it via PHP with PHP SDK2.
I have a little problem.. I've launched job to get ArchiveID:
$this->client->initiateJob(array(
'accountId' => '-',
'vaultName' => $aValutName,
'Type' => "inventory-retrieval")
);
after a couple of hours a can see that job has finished, so I am trying to get job's using it's ID:
$res = $this->client->getJobOutput(array(
'accountId' => '-',
'vaultName' => $aValutName,
'jobId' => $aJobID,
));
and as a respons I am given such things:
Guzzle\Service\Resource\Model Object
(
[structure:protected] =>
[data:protected] => Array
(
[body] => Guzzle\Http\EntityBody Object
(
[contentEncoding:protected] =>
[rewindFunction:protected] =>
[stream:protected] => Resource id #152
[size:protected] =>
[cache:protected] => Array
(
[wrapper_type] => PHP
[stream_type] => TEMP
[mode] => w+b
[unread_bytes] => 0
[seekable] => 1
[uri] => php://temp
[is_local] => 1
[is_readable] => 1
[is_writable] => 1
)
[customData:protected] => Array
(
[default] => 1
)
)
[checksum] =>
[status] => 200
[contentRange] =>
[acceptRanges] => bytes
[contentType] => application/json
[archiveDescription] =>
)
)
Has enybody idea why "archiveDescription" is empty?
Maybe there is another way to obtain ArchiveID so I would be able to delete my archive....
Thanx for any help ;D
MK.
OK, the solution was too easy...
public function getJobResult($aValutName, $aJobID) {
$res = $this->client->getJobOutput(array(
'accountId' => '-',
'vaultName' => $aValutName,
'jobId' => $aJobID,
));
$body = EntityBody::factory($res['body']);
$body->rewind();
$inventory = stream_get_contents($body->getStream());
$ArchiveList = json_decode($inventory,1)['ArchiveList'];
$res = array();
foreach($ArchiveList as $archive):
$res[]=$archive['ArchiveId'];
endforeach;
return $res;
}
I am currently using a datareader as the source but I want to instead use a dataset.
//datareader
AutoMapper.Mapper.CreateMap<IDataReader, AccountDTO>()
.ForMember(m => m.AccountId, opt => opt.MapFrom (r => r.GetInt32(r.GetOrdinal("AccountId"))))
.ForMember(m => m.ParentAccountId, opt => opt.MapFrom(r => r.GetInt32(r.GetOrdinal("ParentAccountId"))))
.ForMember(m => m.IsInactive, opt => opt.MapFrom(r => r.GetString(r.GetOrdinal("IsInactive"))))
.ForMember(m => m.AccountName, opt => opt.MapFrom(r => r.GetString(r.GetOrdinal("AccountName"))))
//dataset
AutoMapper.Mapper.CreateMap<DataSet, AccountDTO>()
.ForMember(m => m.AccountId, opt => opt.MapFrom(r => r.Tables[0].Columns[Constants.MappingFields.Accounts.AccountId]))
.ForMember(m => m.ParentAccountId, opt => opt.MapFrom(r => r.Tables[0].Columns[Constants.MappingFields.Accounts.ParentAccountId]))
.ForMember(m => m.IsInactive, opt => opt.MapFrom(r => r.Tables[0].Columns[Constants.MappingFields.Accounts.IsInactive]))
.ForMember(m => m.AccountName, opt => opt.MapFrom(r => r.Tables[0].Columns[Constants.MappingFields.Accounts.AccountName]))
.ForMember(m => m.AccountNumber, opt => opt.MapFrom(r => r.Tables[0].Columns[Constants.MappingFields.Accounts.AccountNumber]))
any ideas?
I want to use the dataset instead of the datareader so I dont keep the connection to the database open.
I think I have found the solution;
Create the dataset and close/dispose the connection
create a datatablereader from the datatable and pass the in
This seems to be working.
DataTableReader dataTableReader = ds.Tables[0].CreateDataReader();
conn101.Close();
conn101.Dispose();
List<AccountDTO> accountDto1s = Mapper.Map<IDataReader, List<AccountDTO>>(dataTableReader);