How To Write - If Item Does Not Match Multiple Numbers - In Swift? - ios

I have a grid of buttons 11 buttons x 7 buttons. I need to check the tags of the buttons that are not on the outside edge of the grid. My current solution is to exclude the tags that are on the outside edge. The buttons are in an outlet collection. So the tags I need to exclude are 0-10, 21, 32, 43, 54, 65, 76, 0, 11, 22, 33, 44, 55, 66-76.
How do you check if an item in an if-statement, that's inside of a for-loop, matches multiple numbers? You can see the code below will become a mess if I play it out with 28 different || conditions. The numbers I'm trying to match are not in sequence.
for item in buttonOutlets {
if item.tag != 0 || item.tag != 1 || item.tag != 2 {
var tag = item.tag
var tagMinusOne: Int? = Int(item.tag) - 1
var tagMinusTen: Int? = Int(item.tag) - 10
var tagMinusEleven: Int? = Int(item.tag) - 11
var tagMinusTwelve: Int? = Int(item.tag) - 12
var titleLabel = item.titleLabel?.text
var minusTwelve: String? = buttonOutlets[tagMinusTwelve!].titleLabel?.text!
var minusOne: String? = buttonOutlets[tagMinusOne!].titleLabel?.text!
}
}
Here is what works but is a mess. Note that the tags are not in a perfect range. Updated code:
func checkForMatchingCells() {
for item in buttonOutlets {
var tag = item.tag as Int
if tag != 0
&& tag != 1
&& tag != 2
&& tag != 3
&& tag != 4
&& tag != 5
&& tag != 6
&& tag != 7
&& tag != 8
&& tag != 9
&& tag != 10
&& tag != 11
&& tag != 12
&& tag != 33
&& tag != 44
&& tag != 55
&& tag != 21
&& tag != 32
&& tag != 43
&& tag != 54
&& tag != 65
&& tag != 66
&& tag != 67
&& tag != 68
&& tag != 69
&& tag != 70
&& tag != 71
&& tag != 72
&& tag != 73
&& tag != 74
&& tag != 75
&& tag != 76 {
println(tag)
var tagMinusOne: Int? = Int(item.tag) - 1
var tagMinusTen: Int? = Int(item.tag) - 10
var tagMinusEleven: Int? = Int(item.tag) - 11
var tagMinusTwelve: Int? = Int(item.tag) - 12
var titleLabel = item.titleLabel?.text
var minusTwelve: String? = buttonOutlets[tagMinusTwelve!].titleLabel?.text
var minusOne: String? = buttonOutlets[tagMinusOne!].titleLabel?.text
println(minusOne)
}
}

I can think of two ways. First is with ClosedIntervals:
(0...10).contains(3) // true
Or if you have more complex numbers, you can use contains methods on other CollectionTypes:
Set([2, 5, 8]).contains(5) // true
Although I'm not sure what you're trying to do. (The statement x != 0 || x != 1 || x != 2 will return true for every number, for example. Maybe you meant x != 0 && x != 1 && x != 2?)
With your edit, the most effecient solution is to create a Set of things you want to exclude:
var toExclude: Set = [21, 32, 43, 54, 65, 76, 0, 11, 22, 33, 44, 55]
toExclude.unionInPlace(0...10)
toExclude.unionInPlace(66...76)
And then the condition in your if statement would be:
if !toExclude.contains(item.tag) {...

Related

how to use modifying for-loop in Swift 3.2?

I have a converted for-loop in Swift 3.2 that looks similar to this:
for var i in 0..<char.characters.count {
if(self.characters.count > len && ((currentIndex + length2323) < length))
{
i = i - 1
}
}
But, It doesn't work properly. I want to continue loop when set value for i is i = i - 1 but this code getting out of loop
And my previous Swift 2 code is :
for(var i = 0 ; i < char.characters.count ; i += 1) {
if(self.characters.count > len && ((currentIndex + length2323) < length))
{
i = i - 1
}
}
for (index, item) in char.enumerated()
{
//your loop
}
Swift 4 syntax
import UIKit
var char = "char"
var len = 9
var currentIndex = 1
var length2323 = 2323
var length = 17
for var i in 0..<char.count {
if (self.count > len) && ((currentIndex + length2323) < length) {
i = i - 1
}
}
Swift 3.2 syntax
import UIKit
var char = "char"
var len = 9
var currentIndex = 1
var length2323 = 2323
var length = 17
for var i in 0..<char.characters.count {
if (self.characters.count > len) && ((currentIndex + length2323) < length) {
i = i - 1
}
}

How to break up expressions involve bitwise shift operators? Swift

The code below is generating an error and fails to run as the expression was too 'complex'.
for row in 0...NumRows {
for column in 0...NumColumns {
let topLeft = (column > 0) && (row < NumRows)
&& level.tileAt(column: column - 1, row: row) != nil
let bottomLeft = (column > 0) && (row > 0)
&& level.tileAt(column: column - 1, row: row - 1) != nil
let topRight = (column < NumColumns) && (row < NumRows)
&& level.tileAt(column: column, row: row) != nil
let bottomRight = (column < NumColumns) && (row > 0)
&& level.tileAt(column: column, row: row - 1) != nil
let value = Int(topLeft.hashValue) | Int(topRight.hashValue) << 1 | Int(bottomLeft.hashValue) << 2 | Int(bottomRight.hashValue) << 3
if value != 0 && value != 6 && value != 9 {
let name = String(format: "Tile_%ld", value)
let tileNode = SKSpriteNode(imageNamed: name)
tileNode.size = CGSize(width: TileWidth, height: TileHeight)
var point = pointFor(column: column, row: row)
point.x -= TileWidth/2
point.y -= TileHeight/2
tileNode.position = point
tilesLayer.addChild(tileNode)
}
}
}
Specifically this line:
let value = Int(topLeft.hashValue) | Int(topRight.hashValue) << 1 | Int(bottomLeft.hashValue) << 2 | Int(bottomRight.hashValue) << 3
The error is as follows:
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
How would you break up the expression for value in such a way that the code following it keeps the same answer?
hashValue is already an Int, so the Int(...) constructors are not
needed. This compiles in Xcode 9:
let value = topLeft.hashValue | (topRight.hashValue << 1) | (bottomLeft.hashValue << 2) | (bottomRight.hashValue << 3)
But that is a bad idea! It relies on the hash value of booleans having specific values:
false.hashValue == 0
true.hashValue == 1
which is nowhere guaranteed. (The only guarantee is that identical elements have the same hash value. One must not even assume that hash
values are equal across different executions of your program,
see Hashable).
A better solution would be
let value = (topLeft ? 1 : 0) + (topRight ? 2 : 0) + (bottomLeft ? 4 : 0) + (bottomRight ? 8 : 0)
Alternatively, use a switch-statement. Example:
switch (topLeft, topRight, bottomLeft, bottomRight) {
case (false, false, false, false):
// ... all false ...
case (false, true, true, false):
// ... topRight and bottomLeft are true ...
case (true, false, false, true):
// ... topLeft and bottomRight are true ...
default:
// ... all other cases ...
}

Real length of a Thai UTF-8 encoded string in Delphi

Thai is a very special language. You can write vowels (32 in total) as in any other languages right after the consonant, or IN FRONT of it, or ON TOP of it, or ON THE BOTTOM of it (ok, just the short and long "u" sound can go on the bottom, but anyway...).
Furthermore, there are other modifiers (the 4 tone markers, the ga-ran, the mai-tai-ku and other ones) that can go ON TOP of an already existing vowel!
For example:
ที่ดีที่สุด (the best)
As you can see, if I try to print it with a monospaced font, the "real length" would be of 5 characters, but all the UTF-8 strlen routines give me back 11 characters - which is TOTALLY CORRECT, but I need to know the "actual space" that the string will use on screen/on printer, when printed monospaced.
Sure, an easy solution would be to list all the special characters that can go on the top or on the bottom of the word, and remove them from the total count.
Since I am not sure I can find all the special characters, is there already a routine made in any language so that I can translate it in Delphi?
Thank you
In C++:
/*---------------------------------------------------------------------------*/
/* thai_tcslen */
/*---------------------------------------------------------------------------*/
long thai_tcslen(_TCHAR *buff)
{
long bufpos = 0;
long normal_length = _tcslen(buff);
long thai_length = 0;
for (bufpos = 0; bufpos < normal_length; ++bufpos) {
if ( *(buff+bufpos) != _T('Ñ')/*mai han na kaad*//*-047*/
&& *(buff+bufpos) != _T('Ô')/*sara ee *//*-044*/
&& *(buff+bufpos) != _T('Õ')/*sara eeeee *//*-043*/
&& *(buff+bufpos) != _T('Ö')/*sara uu *//*-042*/
&& *(buff+bufpos) != _T('×')/*sara uuuuu *//*-041*/
&& *(buff+bufpos) != _T('Ø')/*sara oo *//*-040*/
&& *(buff+bufpos) != _T('Ù')/*sara ooooo *//*-039*/
&& *(buff+bufpos) != _T('ç')/*mai tai khoo *//*-025*/
&& *(buff+bufpos) != _T('è')/*mai aek *//*-024*/
&& *(buff+bufpos) != _T('é')/*mai toe *//*-023*/
&& *(buff+bufpos) != _T('ê')/*mai cha ta wah *//*-022*/
&& *(buff+bufpos) != _T('ë')/*mai tree *//*-021*/
&& *(buff+bufpos) != _T('ì')/*ka ran *//*-020*/
) {
++thai_length;
}
}
return thai_length;
} /* thai_tcslen */
in VB6:
Public Function ThaiStringLength(ByRef ThaiString As String) As Long
Dim b As String, noLengthChars(13) As Byte
b = ThaiString
noLengthChars(0) = 209
noLengthChars(1) = 212
noLengthChars(2) = 213
noLengthChars(3) = 214
noLengthChars(4) = 215
noLengthChars(5) = 216
noLengthChars(6) = 217
noLengthChars(7) = 231
noLengthChars(8) = 232
noLengthChars(9) = 233
noLengthChars(10) = 234
noLengthChars(11) = 235
noLengthChars(12) = 236
Dim o As Long
For o = 0 To 12
If InStr(b, Chr(noLengthChars(o))) > 0 Then
b = Replace(b, Chr(noLengthChars(o)), "")
End If
Next
ThaiStringLength = Len(b)
End Function

Limit lines and characters per line in textarea

After looking at many solutions, I got the following solutions that does exactly what I want.
SOLUTION 1 : works well except it does not work in IE(11)
I will much appreciate if someone can help me out fixing this for IE.
code taken from :https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement
function checkRows(oField, oKeyEvent) {
var nKey = (oKeyEvent || /* old IE */ window.event || /* check is not supported! */ { keyCode: 38 }).keyCode,
// put here the maximum number of characters per line:
nCols = 30,
// put here the maximum number of lines:
nRows = 5,
nSelS = oField.selectionStart, nSelE = oField.selectionEnd,
sVal = oField.value, nLen = sVal.length,
nBackward = nSelS >= nCols ? nSelS - nCols : 0,
nDeltaForw = sVal.substring(nBackward, nSelS).search(new RegExp("\\n(?!.{0," + String(nCols - 2) + "}\\n)")) + 1,
nRowStart = nBackward + nDeltaForw,
aReturns = (sVal.substring(0, nSelS) + sVal.substring(nSelE, sVal.length)).match(/\n/g),
nRowEnd = nSelE + nRowStart + nCols - nSelS,
sRow = sVal.substring(nRowStart, nSelS) + sVal.substring(nSelE, nRowEnd > nLen ? nLen : nRowEnd),
bKeepCols = nKey === 13 || nLen + 1 < nCols || /\n/.test(sRow) || ((nRowStart === 0 || nDeltaForw > 0 || nKey > 0) && (sRow.length < nCols || (nKey > 0 && (nLen === nRowEnd || sVal.charAt(nRowEnd) === "\n"))));
return (nKey !== 13 || (aReturns ? aReturns.length + 1 : 1) < nRows) && ((nKey > 32 && nKey < 41) || bKeepCols);
}
<form>
<p>Textarea with fixed number of characters per line:<br />
<textarea cols="50" rows="10" onkeypress="return checkRows(this, event);" onpaste="return false;" /></textarea></p>
</form>
SOLUTION 2
It works in IE but it fails in when editing the lines. You type a line, go back using left arrow keys and type you can type 1 letter and the cursor goes back to the end.
code taken from : http://cgodmer.com/?p=55 that
//limit # of lines of a text area and length of those lines
//<textarea rows="4" chars="40" onkeyup="limitTextareaLine(this, event)" ></textarea>
//Author: CGodmer (Feb 22, 2012)
function limitTextareaLine(x, e, nRows, nChars) {
var rows = $(x).val().split("\n").length; //number of rows
var lineCharLimit = nChars; //number of characters to limit each row to
var rowLimit = nRows; //number of rows to allow
//limit length of lines
for (var i = 0; i < rows; i++) {
var rowLength = $(x).val().split("\n")[i].length;
//check to see if any of the rows have a length greater than the limit
if (rowLength > lineCharLimit) {
//if it does save the beg index of the row
var rowstartindex = $(x).val().indexOf($(x).val().split("\n")[i]);
//use the index to get a new value w/ first lineCharLimit number of characters
var newval = $(x).val().substring(0, rowstartindex + lineCharLimit)
+ $(x).val().substring(rowstartindex + rowLength, $(x).val().length);
//replace that value in the textarea
$(x).val(newval);
//set character position back to end of the modified row
setCaretPosition($(x)[0], rowstartindex + lineCharLimit);
}
}
//limit # of lines to limit to is rows attribute
while($(x).val().split("\n").length > rowLimit) {
$(x).val($(x).val().substring(0, $(x).val().length - $(x).val().split("\n")[rowLimit].length - 1));
}
}
//Set caret position in the supplied control to position
//From: http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/
function setCaretPosition(ctrl, pos) {
if (ctrl.setSelectionRange) {
ctrl.focus();
ctrl.setSelectionRange(pos, pos);
}
else if (ctrl.createTextRange) {
var range = ctrl.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea rows="5" cols="10" onkeyup="limitTextareaLine(this, event, 5, 10)" ></textarea>
Try this one, it may solve this problem.
function ValidationAddress() {
var allText;
allText = document.getElementById("<%= txtAdd1.ClientID %>").value;
allText = document.getElementById('<%=txtAdd1.ClientID%>').value;
var A = allText.split('\n');
var L = A.length;
if (L > 3 && event.keyCode != 8 && event.keyCode != 46) {
alert("You have exceeded maximum limit.Cannot insert more than 3 lines.");
valert = false;
return false;
}
var arr = allText.split("\n");
for (var i = 0; i < arr.length; i++) {
if (arr[i].length > 10) {
alert("You have exceeded the Maximum Limit..Characters per line is 70 in Address Field !");
valert = false;
return false;
}
}
}

if conditional of number and its increment by 16 in iOS [duplicate]

This question already has answers here:
Consecutive Number After 16 in iOS
(4 answers)
Closed 9 years ago.
i have an integer called count , and i want it when it comes 1 or 17 or 33 to forever by the same sequence i.e count += 16
the first ball be unhidden , and the same thing when count comes to 2 or 18 or 34 to forever by the same sequence i.e count += 16 , the second ball to unhidden
at first i typed this code but it is very hard to type all numbers with their increments to the end in if condition
if(count == 1 || count == 17 || count == 33 || count == 49 || count == 65 || count == 81 || count == 97 || count == 113 || count == 129 || count == 145 || count == 161 || count == 177 || count == 193 || count == 209 || count == 225 || count == 241)
{
_firstBall.hidden = NO;
}
if(count == 2 || count == 18 || count == 34 || count == 50 || count == 66 || count == 82 || count == 98 || count == 114 || count == 130 || count == 146 || count == 162 || count == 178 || count == 194 || count == 210 || count == 226 || count == 242)
{
_secondBall.hidden = NO;
}
Try this:
if( ((count-1) % 16) == 0) {
_first.hidden = NO;
}
if( ((count-2) % 16) == 0) {
_secondBall.hidden = NO;
}
The % operator returns the integer remainder (or modulus). Your first sequence: 1, 17, 33 is 16 * n + 1 so the remainder when divided by 16 is 1. Similarly your second second sequence is 16 * n + 2.
So you can:
switch (count % 16) // switch on the remainder of division by 16
{
case 1:
_firstBall.hidden = NO; break;
case 2:
_secondBall.hidden = NO; break;
// add more cases if needed
}

Resources