here is the problem. we have an array that contains three different strings. I want to create a function that when I call the function, it will show me the first string; second call would be second string and third call will show the third string in array.
so how should I write this function?
You can basically use a counter and a return function but since you will be changing a state variable it won't be gas optimized and very unuseful you can check the contract below.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/utils/Counters.sol";
contract ArrayItemReturn {
using Counters for Counters.Counter;
Counters.Counter public indexCounter;
string[] strings = ["string 1", "string 2", "string 3"];
function returnItem() external returns(string memory) {
require(indexCounter.current() < strings.length, "You reached the end of the array");
indexCounter.increment();
return strings[indexCounter.current()-1];
}
}
Another approach could be getting the data from your Dapp since you can just query the index you want.
Related
Forgive all my comments, I'm learning and that keeps me straight. Looking for a better solution to my conditional statement near the bottom and provided the rest for context. Tried out the loop comment suggested, but still not getting the right result as written here
// define the main package file
package main
//importing formatting features for the user I/O and string manipulation packages
//Parenthesis not needed if only importing 1 package
import (
"fmt"
"strings"
)
// defining the main function of the standalone app
func main() {
//initializing a string array
options := []string{"lemon", "orange", "strawberry", "banana", "grape"}
//creating a slice in the array to designate favorites
favFruits := options[0:3]
fmt.Println(options)
//initializing variable for user input
var fruit string
fmt.Print("Favorite Fruit Not Listed: ")
fmt.Scan(&fruit)
//convert response to lowercase
fruitConv := strings.ToLower(fruit)
//conditional statement example
for _, pick := range options {
if pick == fruitConv {
fmt.Println("You were supposed to pick something else")
break
} else {
fmt.Println("Response Accepted!")
break
}
break
}
//adding user inputed favorite fruit to the sliced array
favFruits = append(favFruits, fruitConv)
fmt.Print(favFruits)
}
I got your point. If you go to official Go packages section you will get slices package over there. Ref: slices
There is one function named contains inside the slices package, you can make use of that function. For your simplicity, I have created one example matching with your scenario.
func main() {
//initializing a string array
options := []string{"lemon", "orange", "strawberry", "banana", "grape"}
// assuming fruit as user input
fruit := "lemon"
//conditional statement example
if fruit == "coconut" || fruit == "coconuts" {
fmt.Println("Coconuts are nasty (except on your hair/skin)")
//**there has to be a way to simplify this code if the array grows server-side or something**
} else if slices.Contains(options, fruit) {
fmt.Println("You were supposed to pick something different...")
}
}
Here is the working link :- https://goplay.tools/snippet/bzSm_biR4Vr
Note: Since in your scenario there is lot of such contain checks, I would recommend to use map instead of slice. Internally if you deep dive in conatins function of slice you will get to know.
Is it possible to return an array in solidity?
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
pragma experimental ABIEncoderV2;
contract Test {
constructor() {}
function multiArray() external pure returns (uint256[2][] memory doubleArray) {
doubleArray[0] = [uint(12345678),uint(1234567)];
return doubleArray;
}
}
this does not work, but I thought with solidity > 0.8.0 it should be possible, also with "ABIEncoderV2"?
Nested arrays are still incomplete but they work at a certain level.
Currently, nested arrays can only be used within an internal call to functions that are either private or internal. They should also be stored in storage or memory.
The biggest issue is using them in the calldata as a parameter or return statement which is not yet supported.
I'll recommend trying to find another way to return the nested array information like a mapping, struct, or even returning multiple lists and then working with them inside the function.
Another alternative is to pass the data as bytes and extract the array data or vice-versa. However, this can have a high gas cost on large arrays and some other problems. To use this method you can take advantage of the new ABI encoder.
Solidity support 1D array only. Multidimensional arrays are yet to come.
// SPDX-License-Identifier: GPL-3.0;
pragma solidity >=0.7.0 <0.9.0;
contract Test{
string[] A=["A","B"];
function fun() public view returns(string[] memory){
return A;
}
}
Try to initialize the array first and then return values by index. You can also use a mapping, but keep in mind you can't easily iterate over it.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract NestedArrays{
mapping(uint256 => uint256[]) mappingArray;
uint256[2][] multiArray;
constructor(){
multiArray.push([1,2]);
multiArray.push([3,4]);
mappingArray[0] = [10,20];
mappingArray[1] = [30,40];
}
function getMultiArray() public view returns(uint256[2][] memory){
return multiArray;
}
function getMultiArrayMember(uint256 index) public view returns(uint256[2] memory){
require(multiArray.length > index, "wrong index");
return multiArray[index];
}
function getMappingArrayMember(uint256 index) public view returns(uint256[] memory){
return mappingArray[index];
}
}
Playground
I'm trying to store a string into a slice field inside a struct. This is for collecting data and create a Json to post via to an API.
package main
type response1 struct {
Identifier string `json:"identifier"`
Family string `json:"family"`
Values struct {
Logo []struct {
Data string `json:"data"`
Scope string `json:"scope"`
} `json:"logo"`
}
}
func main() {
res2D := &response1{
Identifier: "1234567",
Family: "example",
}
res2D.Values.Logo[0].Data = "test"
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))
}
Error
And the error I got:
panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
/tmp/sandbox507443306/main.go:22 +0xe0
You do not have to make the slice with appropriate size before hand. You can use append. What you are trying to do in your example is assign a slice "[0]" that has not been created yet, which is why you are getting your error. Use append and change your line
res2D.Values.Logo[0].Data = "test"
to
res2D.Values.Logo = append(res2D.Values.Logo,struct {Data string "json:\"data\"" }{Data: "test"})
and that will append the literal struct into your array. Now by looking at your code I am assuming you doing this as a test to explore the language so I wont go into detail on how to better write this without knowing what you are actually using it for.
I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.
Using getDefinitionByName I am consistently getting the error saying it is not defined (as the title says). The particular code I am using is
var tileID:String = String(getDefinitionByName("evt.target.data."+mapData[i][j]))
mapData is already populated by a character in each position. The plan is that I can use the value of whatever mapData is as the variable name for the conversion of the single character to the full linkage name of a tile. These properties come from another external .txt file that is setup for variables (this is the external file the code line links to).
The variables in the external file look something like &N=exampleTile.
So when it comes to setting tileID it should end up being exampleTile. (Assuming mapData[i][j] = "N").
But it doesn't. I have read around at other solutions saying that the file may not have loaded or anything, but I can't make sense of or apply any of those fixes.
As Florian points out, getDefinitionByName is specifically for getting a Class reference. Something like "flash.net.URLLoader" would give you a reference to the URLLoader class for example. It's not used for getting regular variables by their names (so "evt.target.data.N" wouldn't return anything even if "N" was a property of data).
It sounds like your evt.target.data is a long string along the lines of "A=tileA&B=tileB&C=tileC". If so, you need to parse that string out to separate variables first. You should be able to use URLVariables with that data format (flash.net.URLVariables), then you can read the parsed variables using the [ ] array access operator: urlVariablesObject["variableName"]. So you might do something like this:
import flash.events.Event;
import flash.net.URLVariables;
import flash.net.URLLoader;
import flash.net.URLRequest;
var loader:URLLoader = new URLLoader();
var parsedData:URLVariables;
var mapData:Array = [["A", "B", "C"], ["D", "E", "F"]];
loader.addEventListener(Event.COMPLETE, externalFileLoaded);
loader.load(new URLRequest("externalFile.txt"));
// externalFile.txt contains "A=tileA&B=tileB&C=tileC&D=tileD&E=tileE&F=tileF".
function externalFileLoaded(evt:Event):void {
parsedData = new URLVariables(evt.target.data);
var tileID:String = readMap(0, 1);
trace(tileID); // "tileB".
}
function readMap(i:uint, j:uint):String {
var mapValue:String = mapData[i] [j];
var tileID:String = parsedData[mapValue];
return tileID;
}
That doesn't make any sense. getDefinitionByName is used to retrieve a Class instance of a certain type - the Class named like the string passed. And the definition will always start with "evt.target.data.".
Did you ever debugged your way through it?
function any_handler(i:int, j:int):void {
const suffix:String = mapData[i][j],
qualifiedName:String = "evt.target.data." + suffix;
// this is wrong
const titleID:String = String(getDefinitionByName(qualifiedName));
}
You really should take a look in the debugger in order to know the value of the string you are creating.