Make 1 associative array out of 2 arrays in Actionscript 3 - arrays

How do i make 1 array that has the keys of 1st array & its values are the values of the 2nd array in Actionscript 3.0?
Below is my [WRONG] code. Package import left out.
public class myPages extends Sprite {
protected var pageNames:Array = [];
protected var pageLayoutNo:Array = [];
private var pageLayoutNames:Object = new Object();
public function assignNamesLayouts {
//all the names of the pages
for(i=0; i<totalPages; i++) {
var pageMc:MovieClip=new MovieClip();
pageMc.name = menu.config.pages.page[i].#name;
pageNames[i]= pageMc.name;
}
//all layout numbers
for(i=0; i<totalPages; i++) {
pageLayoutNo[i] = menu.config.layoutNum.layNum[i];
}
setNames(pageNames);
setPLNo(pageLayoutNo);
setLayoutNames(pageLayoutNo,pageNames);
}
protected function setNames(a:Array) {
pageNames = a;
}
protected function setPLNo(a:Array) {
pageLayoutNo = a;
}
protected function setLayoutNames(a:Array, b:Array) {
var maps:Object = new Object();
maps.no = a;
maps.nm = b;
for each(var k:int in a) {
maps[k] = b;
}
}
}
Thank you.

I will agree with #Vesper. Closest solution to the associative array will be Dictionary. I also will add, some ideas for you. If your collection will have keys as Strings, you could use simple Object:
var keyName: String = "key1";
var anotherKey: String = "key2";
var collection: Object = {};
collection[keyName] = new MovieClip();
collection[anotherKey] = new Sprite();
trace(collection[keyName]);
If you want to use 2 arrays: one for keys, another one for values, you will need several functions(place object with key, get object by key, get object by value, remove object by key, etc.) to manage them, because indexes in arrays must be identical.

Dictionary is really what you want, but you could do it by creating an array of objects like this:
var newArray=combineArrays("name", arr1,"number",arr2);
function combineArrays(name1, arr1,name2, arr2){
var newArr=new Array();
for(var i<arr1){
var obj=new Object();
obj[name1]=arr1[i];
obj[name2]=arr2[i];
newArr.push(obj);
}
}
Then you can search on the object names or values for either object.

Related

Mutate Model Struct in a ForEach - Swift/SwiftUI [duplicate]

I am still not sure about the rules of struct copy or reference.
I want to mutate a struct object while iterating on it from an array:
For instance in this case I would like to change the background color
but the compiler is yelling at me
struct Options {
var backgroundColor = UIColor.blackColor()
}
var arrayOfMyStruct = [MyStruct]
...
for obj in arrayOfMyStruct {
obj.backgroundColor = UIColor.redColor() // ! get an error
}
struct are value types, thus in the for loop you are dealing with a copy.
Just as a test you might try this:
Swift 3:
struct Options {
var backgroundColor = UIColor.black
}
var arrayOfMyStruct = [Options]()
for (index, _) in arrayOfMyStruct.enumerated() {
arrayOfMyStruct[index].backgroundColor = UIColor.red
}
Swift 2:
struct Options {
var backgroundColor = UIColor.blackColor()
}
var arrayOfMyStruct = [Options]()
for (index, _) in enumerate(arrayOfMyStruct) {
arrayOfMyStruct[index].backgroundColor = UIColor.redColor()
}
Here you just enumerate the index, and access directly the value stored in the array.
Hope this helps.
You can use use Array.indices:
for index in arrayOfMyStruct.indices {
arrayOfMyStruct[index].backgroundColor = UIColor.red
}
You are working with struct objects which are copied to local variable when using for in loop. Also array is a struct object, so if you want to mutate all members of the array, you have to create modified copy of original array filled by modified copies of original objects.
arrayOfMyStruct = arrayOfMyStruct.map { obj in
var obj = obj
obj.backgroundColor = .red
return obj
}
It can be simplified by adding this Array extension.
Swift 4
extension Array {
mutating func mutateEach(by transform: (inout Element) throws -> Void) rethrows {
self = try map { el in
var el = el
try transform(&el)
return el
}
}
}
Usage
arrayOfMyStruct.mutateEach { obj in
obj.backgroundColor = .red
}
For Swift 3, use the enumerated() method.
For example:
for (index, _) in arrayOfMyStruct.enumerated() {
arrayOfMyStruct[index].backgroundColor = UIColor.redColor()
}
The tuple also includes a copy of the object, so you could use for (index, object) instead to get to the object directly, but since it's a copy you would not be able to mutate the array in this way, and should use the index to do so. To directly quote the documentation:
If you need the integer index of each item as well as its value, use
the enumerated() method to iterate over the array instead. For each
item in the array, the enumerated() method returns a tuple composed of
an integer and the item.
Another way not to write subscript expression every time.
struct Options {
var backgroundColor = UIColor.black
}
var arrayOfMyStruct = [Options(), Options(), Options()]
for index in arrayOfMyStruct.indices {
var option: Options {
get { arrayOfMyStruct[index] }
set { arrayOfMyStruct[index] = newValue }
}
option.backgroundColor = .red
}
I saw this method in some code and it seems to be working
for (var mutableStruct) in arrayOfMyStruct {
mutableStruct.backgroundColor = UIColor.redColor()
}

Finding two similar arrays using streams

Let's say I have list of objects, each containing own array of Strings. I need to find objects that have most duplicates with given array.
I can simply achive that by using some for loops, if and counters, but I want to do that using Java 8 streams. I really hope it is possible.
#Test
public void test() {
String mainArray[] = {"a", "b", "c"};
List<ElementsList> elems = new ArrayList<>();
ElementsList a = new ElementsList(new String[]{"d", "e", "a"});
ElementsList b = new ElementsList(new String[]{"b", "c", "d"});
elems.add(a);
elems.add(b);
List<ElementsList> result = elems.stream()...;
assertTrue(result.contains(b));
}
private class ElementsList {
private String elements[];
private ElementsList(String elements[]) {
this.elements = elements;
}
public String[] getElements() {
return elements;
}
}
I can think of this for example:
List<String> main = Arrays.asList(mainArray);
Stream.of(a, b)
.map(x -> new AbstractMap.SimpleEntry<>(x, new ArrayList<>(new ArrayList<>(Arrays.asList(x.elements)))))
.map(entry -> {
entry.getValue().removeAll(main);
entry.setValue(entry.getValue());
return entry;
})
.sorted(Comparator.comparing(e -> e.getValue().size()))
.map(Entry::getKey)
.forEach(el -> System.out.println(Arrays.toString(el.elements)));
Basically put all the elements into a mutable List and do a removeAllof the ones from mainArray and sort the result based on the size of the remaining ones.
Here's a straightforward approach:
import static java.util.Comparator.comparingLong;
Set<String> mainSet = new HashSet<>(Arrays.asList(mainArray));
ToLongFunction<ElementsList> countMatches = el ->
Arrays.stream(el.getElements())
.filter(mainSet::contains)
.count();
ElementsList result = elems.stream()
.max(comparingLong(countMatches))
.get(); // or throw if elems is empty
This solution is better when lists have different sizes.
List<String> main = Arrays.asList(mainArray);
Stream.of(a, c, b)
.map(x -> new AbstractMap.SimpleEntry<>(x, new ArrayList<>(main)))
.peek(entry -> {
entry.getValue().removeAll(Arrays.asList(entry.getKey().elements));
entry.setValue(entry.getValue());
})
.sorted(Comparator.comparing(e -> e.getValue().size()))
.map(Map.Entry::getKey)
.forEach(el -> System.out.println(Arrays.toString(el.elements)));

Swift: using a for loop to insert items. At the end, when i query it shows only the value which was inserted last at each index

In Swift playground, I'm using a for loop to insert items. During the loop it seems to be adding the right values. At the end of the for loop, when the array is all filled up, when I query, it shows only the value which was inserted last at each index.
New to swift, so I guess am doing something really stupid here... Need help...
The code is as below:
class card {
var suit: String = ""
var rank: String = ""
}
var card1 = card()
var deck = [card]()
var playingCard = card()
var suits = ["♠︎","♣︎","♥︎","♦︎"]
var ranks = ["A","K","Q","J","10","9","8","7","6","5","4","3","2"]
let countRanks = ranks.count
let countSuits = suits.count
var ctr = 0
for i in 0..<countSuits {
for j in 0..<countRanks {
playingCard.rank = ranks[j]
playingCard.suit = suits[i]
deck.insert(playingCard, atIndex: 0)
println("\(deck[ctr].suit)"+"\(deck[ctr].rank)")
ctr++
}
}
let x = deck.count
for i in 0..<x {
println("\(deck[i].rank)"+"\(deck[i].suit)")
}
class instances are reference types. You need to create a new card instance for each iteration. Move the line var playingCard = card() right after the for j in 0..<countRanks line and change var to let
You need to initialise a new instance of playingCard each iteration:
for i in 0..<countSuits {
for j in 0..<countRanks {
var playingCard = card()
...
}
}
I would also suggest you add an init method for your card class to make it easier to initialise:
class Card {
var suit: String
var rank: String
init(suit: String, rank: String) {
self.suit = suit
self.rank = rank
}
}
...
var playingCard = Card(suit: suits[i], rank: ranks[j])

Why can't I use the array's append() in Swift?

I'm getting a: Cannot invoke 'append' with an argument list of type '([Book])' It works find if I use the += but I don't understand why append() won't work.
struct Book
{
var title:String
var pageCount:Int
}
class Library
{
var onShelfBooks:[Book] = []
var onLoanBooks:[Book] = []
var books:[Book]
{
get
{
return onShelfBooks + onLoanBooks
}
set(newBook)
{
onShelfBooks.append(newBook)
}
}
}
struct Book
{
var title:String
var pageCount:Int
}
class Library
{
var onShelfBooks:[Book] = []
var onLoanBooks:[Book] = []
var books:[Book]
{
get
{
return onShelfBooks + onLoanBooks
}
set(newBook)
{
onShelfBooks.append(newBook[0])
}
}
}
var myLibrary = Library()
var newBook = Book(title: "Swift Development with Cocoa", pageCount: 453)
myLibrary.books = [newBook]
myLibrary.books
Append only allows you to add one object at a time while += allows you to combine an array of objects with another object. When you call append on the setter you are trying to add an array of book objects, or [Book] instead of just a single book object.
If you would like to add [newBook] with append, you can use : of
1- onShelfBooks.append(contentsOf: newBook)
"contentOf" is type of Sequence.
otherwise use of:
2- onShelfBooks += newBook

Convert Vector.<SomeType> to Array?

Unfortunately in Actionscript, it seems like support for the Vector class isn't fully there yet. There are some scenarios where I need to convert a Vector into an array (creating an ArrayCollection for example). I thought this would do the trick:
var myVector:Vector.<MyType> = new Vector.<MyType>();
var newArray:Array = new Array(myVector);
Apparently this just creates an array where the first index of the array contains the full Vector object. Is this my only option:
var newArray:Array = new Array(myVector);
for each(var item:MyType in myVector)
{
newArray.push(item);
}
I feel like that clutters up the code a lot and I need to do this in a lot of places. The Vector class doesn't implement any kind of interface, so as far as I can tell I can't create a generic function to convert to an array. Is there any way to do this without adding this mess every time I want to convert a Vector to an array?
There's no easy/fast way to do it, the best solution is to use an utility class like this one:
package {
public class VectorUtil {
public static function toArray(obj:Object):Array {
if (!obj) {
return [];
} else if (obj is Array) {
return obj as Array;
} else if (obj is Vector.<*>) {
var array:Array = new Array(obj.length);
for (var i:int = 0; i < obj.length; i++) {
array[i] = obj[i];
}
return array;
} else {
return [obj];
}
}
}
}
Then you just have to update your code to something like this:
var myArray:Array = VectorUtil.toArray(myVector);
Paul at Work found a better way to do it.
var newArray:Array = [].concat(myVector);

Resources