My Array:
let array = [45,12,10,90]
// The number I need in this case is 3
Then I need to grab a value of another array:
let otherArray = [6,6,7,4,0]
I have tried to resolve the problem like this:
let maxPosition = array.max()
let desiredValue = otherArray[maxPosition]
This doesn't seem to work as desired.
Thanks for your help!
The problem there is that max returns the maximum value from your array, not an index. You need to find the index of the maximum value and use it with your other array:
let array = [45,12,10,90]
let otherArray = [6,6,7,4,0]
if let maxValue = array.max(), let index = array.index(of: maxValue) {
let desiredValue = otherArray[index]
print(desiredValue) // 4
}
Another option is to use your collection indices when getting the maximum value:
if let index = array.indices.max(by: { array[$0] < array[$1] }) {
let desiredValue = otherArray[index]
print(desiredValue) // 4
}
Here is another approach:
let array = [45,12,10,90]
let otherArray = [6,6,7,4,0]
var maxValueInArray = array[0]
for i in 1..<array.count{
if array[i] > maxValueInArray{
maxValueInArray = array[i]
}
}
if let maxValueIndex = array.index(of: maxValueInArray){
let desiredValueInOtherArray = otherArray[maxValueIndex]
print("Maximum value in array is \(maxValueInArray) with index \(maxValueIndex). Value in otherArray under index \(maxValueIndex) is \(desiredValueInOtherArray)")
}
You could find the index of the highest value by comparing the elements in the array to its highest value:
let array = [45,12,10,90]
let otherArray = [6,6,7,4,0]
if let index = array.firstIndex(where: { $0 == array.max() }) {
print(otherArray[index]) //4
}
Just be mindful that the two arrays are of different sizes, therefore the index of the highest value in one array could be out-of-bounds in the other array.
Related
I am trying to generate 5 random substrings of six characters each from the alphabet. For example: ABCDEF, RSTUVW, UVWXYZ, etc. These substrings can be duplicates, so generating ABCDEF twice is a not a problem.
When I have these 5 substrings, I want to generate five arrays containing three characters. One of these characters should be the last letter of the substring and the other two letters should be two random unique letters from the entire alphabet.
Example:
Get five random substrings:
[ABCDEF], [RSTUVW], [CDEFGH], [LMNOPQ], [UVWXYZ]
For [ABCDEF] the system could generate [F, H, S] and for [RSTUVW] it could generate [K, Q, W]. As you can see, the three-character arrays always contain the last letter of its substring and two other randomised unique letters.
The above is part of a game for kids to practice the order of the alphabet. In order to generate possible answers I actually need small sets of characters to assign to buttons.
What do you think is the best way to approach this?
Thanks to #vacawama here's a possible solution.
1. Create the alphabet
let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters)
2. Create the 6 "sequences"
let sequences = (0..<5).map { _ -> String in
let startIndex = Int(arc4random_uniform(UInt32(alphabet.count - 5)))
let endIndex = startIndex + 5
return String(alphabet[startIndex...endIndex])
}
["PQRSTU", "DEFGHI", "JKLMNO", "CDEFGH", "KLMNOP"]
3. Get the last char for each sequence
let lastChars = sequences.flatMap { $0.characters.last }
["U", "I", "O", "H", "P"]
4. Build 5 elms
Here's the code snippet
let elms = lastChars.map { char0 -> String in
var tempAlphabet = alphabet
tempAlphabet.removeAtIndex(tempAlphabet.indexOf(char0)!)
let index1 = Int(arc4random_uniform(UInt32(tempAlphabet.count)))
let char1 = tempAlphabet.removeAtIndex(index1)
let index2 = Int(arc4random_uniform(UInt32(tempAlphabet.count)))
let char2 = tempAlphabet[index2]
return String(Array(Set<Character>([char0, char1, char2])))
}
["DUN", "ZIQ", "ROP", "HSW", "PGS"]
Update
Here's another solution to fix the problem hightligted by #dfri in the comments below. The following code snipped could replace the previous bullet 4.
extension Array {
mutating func removeRandom() -> Element {
let index = Int(arc4random_uniform(UInt32(count)))
return removeAtIndex(index)
}
}
var availableChars = Array(Set(alphabet).subtract(lastChars))
let elms = lastChars.map { String([$0, availableChars.removeRandom(), availableChars.removeRandom()]) }
Random substrings:
func randomString(length: Int) -> String {
let charactersString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let n = UInt32(charactersString.characters.count)
var out = ""
for _ in 0..<length {
let index = charactersString.startIndex.advancedBy(Int(arc4random_uniform(n)))
out.append(charactersString[index])
}
return out
}
Get 5 Strings:
func createSubstrings() -> [String] {
var array = [String]()
for _ in 0...5 {
array.append(self.randomString(6))
}
return array
}
Last array:
func createFinalStrings() -> [String] {
let substrings = createSubstrings()
var finalStrings = [String]()
let lastChars = substrings.flatMap { $0.characters.last }
for _ in 0...5 {
var string = ""
while string.characters.count < 3 {
let index = Int(arc4random_uniform(5))
let lastChar = lastChars[index]
if string.rangeOfString(String(lastChar)) == nil{
string = string + String(lastChar)
}
}
finalStrings.append(string)
}
return finalStrings
}
In Unity Javascript, I cant make PlayerPrefsX to store Array of Strings.
Here are the requirements-
I have an Array of Strings.
Doing Array Push in that.
Now I want to store the item in PlayerPrefX
What I did is-
var storedScoresArr:Array = new
Array();
storedScoresArr.Push(scoreDetails);
PlayerPrefsX.SetStringArray("ScoreDetails",
storedScoresArr); // Gives Error
P.S
I know if I do like the following, it will work; but cant do an Array Push.-
var storedScoresArr:String[] = ["abc", "xyz"]; // it will work
// But
doesn't support ARRAY PUSH
Please help with any workaround or if there is any way to convert the Array to String[] just before storing in PlayerPrefsX.
Stick this in PlayerPrefsX.js
static function SetStringArray (key : String, array : Array) : boolean {
if(array.length == 0) {
Debug.LogError ("The array cannot have 0 entries when setting " + key);
return false;
}
var stringArray : String[] = new String[array.length];
for(var i = 0; i < array.length; i++)
stringArray[i] = array[i].ToString();
return SetStringArray(key, stringArray);
}
I'm not really on point with Swift yet and there is a problem that is starting to be a tad annoying.
I just want to add integer in a double dimensional array but it is always returning the same error code : "fatal error : Array index out of range"
var arrayVolley = [[Int]]()
init(){
self.arrayVolley = [[]]
}
Here is where I try to insert :
func addPoints(score : Int, x : Int, y : Int){
if (score > 11 || score < 0){ //11 will be translated as 10x
println("Error on score value")
}
else {
if (x>6 || y>6){
println("Out of array")
}
else{
arrayVolley[x][y]=score
}
}
}
And this is my main :
var i=0
var j=0
for i in 0...6 {
for j in 0...6{
println("Entrez le score")
var scoreinput=input()
var score = scoreinput.toInt()
distance.addPoints(score!, x: i, y: j)
}
}
Thanks a lot for your help in advance
Try to use append to add the integer to the array it is automatically the next idex. It think if the index was never used it gives an error e.g.
var test = [Int]()
test.append(2) // array is empty so 0 is added as index
test.append(4)
test.append(5) // 2 is added as max index array is not [2,4,5]
test[0] = 3 // works because the index 0 exist cause the where more then 1 element in array -> [3,4,5]
test[4] = 5 // does not work cause index for never added with append
or you intialize the array in the correct size, but it's need a size:
var test = [Int](count: 5, repeatedValue: 0) // [0,0,0,0,0]
test[0] = 3 //[3,0,0,0,0]
test[4] = 5 [3,0,0,0,5]
It hope this helps you if not please feel free to comment.
I need to find the most common (modal) elements in an array.
The simplest way I could think of was to set variables for each unique element, and assign a count variable for each one, which increases every time it is recorded in a for loop which runs through the array.
Unfortunately the size of the array is unknown and will be very large, so this method is useless.
I have come across a similar question in Objective-C that uses an NSCountedSet method to rank the array elements. Unfortunately I am very new to programming, and could only translate the first line into Swift.
The suggested method is as follows:
var yourArray: NSArray! // My swift translation
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:yourArray];
NSMutableDictionary *dict=[NSMutableDictionary new];
for (id obj in set) {
[dict setObject:[NSNumber numberWithInteger:[set countForObject:obj]]
forKey:obj]; //key is date
}
NSLog(#"Dict : %#", dict);
NSMutableArray *top3=[[NSMutableArray alloc]initWithCapacity:3];
//which dict obj is = max
if (dict.count>=3) {
while (top3.count<3) {
NSInteger max = [[[dict allValues] valueForKeyPath:#"#max.intValue"] intValue];
for (id obj in set) {
if (max == [dict[obj] integerValue]) {
NSLog(#"--> %#",obj);
[top3 addObject:obj];
[dict removeObjectForKey:obj];
}
}
}
}
NSLog(#"top 3 = %#", top3);
In my program I will need to find the top five place names in an array.
edit: now with Swift 2.0 below
Not the most efficient of solutions but a simple one:
let a = [1,1,2,3,1,7,4,6,7,2]
var frequency: [Int:Int] = [:]
for x in a {
// set frequency to the current count of this element + 1
frequency[x] = (frequency[x] ?? 0) + 1
}
let descending = sorted(frequency) { $0.1 > $1.1 }
descending now consists of an array of pairs: the value and the frequency,
sorted most frequent first. So the “top 5” would be the first 5 entries
(assuming there were 5 or more distinct values). It shouldn't matter how big the source array is.
Here's a generic function version that would work on any sequence:
func frequencies
<S: SequenceType where S.Generator.Element: Hashable>
(source: S) -> [(S.Generator.Element,Int)] {
var frequency: [S.Generator.Element:Int] = [:]
for x in source {
frequency[x] = (frequency[x] ?? 0) + 1
}
return sorted(frequency) { $0.1 > $1.1 }
}
frequencies(a)
For Swift 2.0, you can adapt the function to be a protocol extension:
extension SequenceType where Generator.Element: Hashable {
func frequencies() -> [(Generator.Element,Int)] {
var frequency: [Generator.Element:Int] = [:]
for x in self {
frequency[x] = (frequency[x] ?? 0) + 1
}
return frequency.sort { $0.1 > $1.1 }
}
}
a.frequencies()
For Swift 3.0:
extension Sequence where Self.Iterator.Element: Hashable {
func frequencies() -> [(Self.Iterator.Element,Int)] {
var frequency: [Self.Iterator.Element:Int] = [:]
for x in self {
frequency[x] = (frequency[x] ?? 0) + 1
}
return frequency.sorted { $0.1 > $1.1 }
}
}
For XCode 7.1 the solution is.
// Array of elements
let a = [7,3,2,1,4,6,8,9,5,3,0,7,2,7]
// Create a key for elements and their frequency
var times: [Int: Int] = [:]
// Iterate over the dictionary
for b in a {
// Every time there is a repeat value add one to that key
times[b] = (times[b] ?? 0) + 1
}
// This is for sorting the values
let descending = times.sort({$0.1 > $1.1})
// For sorting the keys the code would be
// let descending = times.sort({$0.0 > $1.0})
// Do whatever you want with sorted array
print(descending)
Same as Airspeed Velocity, using a reduce instead of for-in:
extension Sequence where Self.Iterator.Element: Hashable {
func frequencies() -> [(Self.Iterator.Element, Int)] {
return reduce([:]) {
var frequencies = $0
frequencies[$1] = (frequencies[$1] ?? 0) + 1
return frequencies
}.sorted { $0.1 > $1.1 }
}
}
But please note that, here, using reduce with a struct is not as efficient as a for-in because of the struct copy cost. So you will generally prefer the for-in way of doing it.
[edit: gosh, the article is by the same guy as the top answer!]
How do you randomize an array using actionscript 3?
There is a short version using Array.sort() function:
var arr : Array = [0,1,2,3,4,5,6,7,8,9];
function randomize ( a : *, b : * ) : int {
return ( Math.random() > .5 ) ? 1 : -1;
}
trace( arr.sort( randomize ) );
If you don't get "enough" randomness you can sort twice :)
EDIT - explanation line by line:
For Array class method sort() you can pass not only sort options like Array.CASEINSENSITIVE, Array.DESCENDING and so on but also your own custom compare function reference (a callback) that accepts two parameters (two elements from array to compare). From AS3 documentation:
A comparison function should take two arguments to compare. Given the elements A and B, the result of compareFunction can have a negative, 0, or positive value:
A negative return value specifies that A appears before B in the sorted sequence.
A return value of 0 specifies that A and B have the same sort order.
A positive return value specifies that A appears after B in the sorted sequence.
Note: compare function parameters might be typed (if your array is typed) and have any name you want eg.:
function compareElements ( elementA : SomeClass, elementB : SomeClass ) : int;
This method is very useful when you need to sort array elements by their special properties. In randomization case compareFunction randomly returns -1, 0 or 1 and makes array elements to switch their places (indices). I have found that better randomization (in my subjective and mathematically untested opinion) is when method returns only -1 and 1. Also have in mind that sorting function with custom compare function doesn't compare elements sequentially so in some special cases randomization results may differ from what you might expect.
There's a better way that will also allow you to randomize the array in place, if you need that, and it will not make you create more then a single copy of your original array.
package
{
import flash.display.Sprite;
public class RandomizeArrayExample extends Sprite
{
public function RandomizeArrayExample()
{
super();
testDistribution();
}
private function testDistribution():void
{
var hash:Object = { };
var tester:Array = [1, 2, 3, 4];
var key:String;
for (var i:int; i < 1e5; i++)
{
randomize(tester);
key = tester.join("");
if (key in hash) hash[key]++;
else hash[key] = 1;
}
for (var p:String in hash) trace(p, "=>", hash[p]);
}
private function randomize(array:Array):Array
{
var temp:Object;
var tempOffset:int;
for (var i:int = array.length - 1; i >= 0; i--)
{
tempOffset = Math.random() * i;
temp = array[i];
array[i] = array[tempOffset];
array[tempOffset] = temp;
}
return array;
}
}
}
I had an alternative requirement where i wanted to randomly insert lots of source arrays into a target array randomly. Like Rytis i'm a big fan of the forEach, map and sort functions on Arrays.
var randomInsert:Function = function callback(item:*, index:int, array:Vector.<MyItem>):void
{
var j:Number = Math.floor(Math.random() * targetArray.length);
targetArray.splice(j,0,item);
}
targetArray = new Vector.<MyItem>();
sourceArray1.forEach(randomInsert, this);
sourceArray2.forEach(randomInsert, this);
here's an easier function. Works also on multidimensional arrays
function randomizeArray(array:Array):Array
{
var newArray:Array = new Array();
while (array.length > 0)
{
var mn=Math.floor(Math.random()*array.length)
newArray[newArray.length]=array[mn]
array.splice(mn,1)
}
return newArray;
}
I found this very helpful. I hope it can help you too.
// Array to Randomize
var firstArray:Array = ["One","Two","Three","Four","Five","six","seven","eight","nine","ten"];
trace(firstArray); // Prints in order
var newArray:Array = new Array();
function randomizeArray(array:Array):Array
{
var newArray:Array = new Array();
while (array.length > 0)
{
newArray.push(array.splice(Math.floor(Math.random()*array.length), 1));
}
return newArray;
}
var randomArray:Array = randomizeArray(firstArray);
trace(randomArray); // Prints out randomized :)
If you need your array to be shuffled (your elements can not repeat). You could use this function:
/**
* Shuffles array into new array with no repeating elements. Simple swap algorithm is used.
*/
public function shuffleArray(original:Array):Array
{
// How many swaps we will do
// Increase this number for better results (more shuffled array, but slower performance)
const runs:int = original.length * 3;
var shuffled:Array = new Array(original.length);
var i:int;
var a:int;
var b:int;
var temp:Object;
// Copy original array to shuffled
for(i=0; i<shuffled.length; i++){
shuffled[i] = original[i];
}
// Run random swap cycle 'runs' times
for(i=0; i<runs; i++){
// There is a chance that array element will swap with itself,
// and there is always small probability it will make your shuffle
// results not that good, hence try to experiment with
// different runs count as stated above
a = Math.floor(Math.random() * original.length);
b = Math.floor(Math.random() * original.length);
// Swap messages
temp = shuffled[a];
shuffled[a] = shuffled[b];
shuffled[b] = temp;
}
return shuffled;
}
Usage:
var testArray:Array = ["Water", "Fire", "Air", "Earth"];
trace(shuffleArray(testArray).concat());
this is how I randomize my array of 36 cards for a memory game
const QUANT_CARTAS: int = 36;
//get the 36 numbers into the array
for (var i: int = 0; i < QUANT_CARTAS; i++)
{
cartas.push(i);
}
//shuffles them =)
for (var moeda: int = QUANT_CARTAS - 1; moeda > 0; moeda--)
{
var pos: int = Math.floor(Math.random() * moeda);
var carta: int = cartas[moeda];
cartas[moeda] = cartas[pos];
cartas[pos] = carta;
}
// and add them using the random order...
for (i = 0; i < QUANT_CARTAS; i++)
{
var novaCarta: Carta = new Carta();
novaCarta.tipoCarta = cartas[i];
etcetcetc.............
}
choose random string from array
function keyGenerator(len:Number):String
{
function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
var hexArray = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
var key = "";
for (var i=0; i<len; i++)
{
key += hexArray[randomRange(0,hexArray.length-1)];
}
return key;
}
usage:
trace(keyGenerator(16));