Binary search to get original index in an Array - arrays

I have an array “a” like the following:
let a = [1.0, 2.0, 10.0, 0.0, 5.0] // original array
I am looking to find the number 10.0 in “a” using binary search.
For that I sort the array to get array “asr”:
let asr = a.sorted()
print(asr)
// [0.0, 1.0, 2.0, 5.0, 10.0]
Binary search for 10.0 in “asr” will return me index = 4. Whereas I am looking for index = 2 as in the original array “a”. And I am also looking for speed since my arrays are long.
Any suggestions?
I paste below the binary search algorithm I am using:
func binarySearch<T:Comparable>(inputArr:Array<T>, searchItem: T)->Int{
var lowerIndex = 0;
var upperIndex = inputArr.count - 1
while (true) {
let currentIndex = (lowerIndex + upperIndex)/2
if(inputArr[currentIndex] == searchItem) {
return currentIndex
} else if (lowerIndex > upperIndex) {
return -1
} else {
if (inputArr[currentIndex] > searchItem) {
upperIndex = currentIndex - 1
} else {
lowerIndex = currentIndex + 1
}
}
}
}
I give example of my x (time) and y (value) arrays. For multiple such arrays, I need to find maximum of values in y and store the related unique x value.
let x = [230.0, 231.0, 232.0, 233.0, 234.0, 235.0, 236.0, 237.0, 238.0, 239.0, 240.0, 241.0, 242.0, 243.0, 244.0, 245.0, 246.0, 247.0, 248.0, 249.0, 250.0, 251.0, 252.0, 253.0, 254.0, 255.0, 256.0, 257.0, 258.0, 259.0, 260.0, 261.0, 262.0, 263.0, 264.0, 265.0, 266.0, 267.0, 268.0, 269.0, 270.0, 271.0, 272.0, 273.0, 274.0, 275.0, 276.0, 277.0, 278.0, 279.0, 280.0, 281.0, 282.0, 283.0, 284.0, 285.0, 286.0, 287.0, 288.0, 289.0, 290.0, 291.0, 292.0, 293.0, 294.0, 295.0, 296.0, 297.0, 298.0, 299.0, 300.0, 301.0, 302.0, 303.0, 304.0, 305.0, 306.0, 307.0, 308.0, 309.0, 310.0, 311.0, 312.0, 313.0, 314.0, 315.0, 316.0, 317.0, 318.0, 319.0, 320.0, 321.0, 322.0, 323.0, 324.0, 325.0, 326.0, 327.0, 328.0, 329.0, 330.0, 331.0, 332.0, 333.0, 334.0, 335.0, 336.0, 337.0, 338.0, 339.0, 340.0, 341.0, 342.0, 343.0, 344.0] // unique ascending time stamps
let y = [-0.0050202642876176198, 0.022393410398194001, 0.049790254951834603, 0.077149678828730195, 0.104451119608423, 0.131674058448602, 0.15879803550636501, 0.185802665315146, 0.21266765210574901, 0.239372805059962, 0.26589805348529699, 0.29222346189943499, 0.31832924501308402, 0.34419578259991401, 0.36980363424246498, 0.39513355394291599, 0.42016650458771598, 0.444883672255248, 0.46926648035572899, 0.49329660359275201, 0.51695598173596602, 0.54022683319452802, 0.56309166838114799, 0.58553330285668204, 0.60753487024536401, 0.62907983491101405, 0.65015200438466503, 0.67073554153427395, 0.690814976467372, 0.71037521815772098, 0.72940156578721904, 0.74787971979453605, 0.765795792622184, 0.783136319153938, 0.79988826683476, 0.816039045465632, 0.83157651666592303, 0.84648900299618601, 0.86076529673452795, 0.87439466829995904, 0.88736687431637595, 0.89967216531114802, 0.91130129304248497, 0.92224551745010597, 0.93249661322397404, 0.94204687598616199, 0.95088912808120296, 0.95901672397057403, 0.96642355522725798, 0.97310405512663301, 0.979053202830236, 0.98426652715924901, 0.98874010995489703, 0.99247058902319396, 0.99545516066186102, 0.99769158176748995, 0.99917817152138799, 0.99991381265282298, 0.99989795227872502, 0.99913060231921702, 0.99761233948865402, 0.99534430486218395, 0.99232820301815805, 0.98856630075702201, 0.98406142539766805, 0.97881696265251605, 0.97283685408292797, 0.96612559413686105, 0.95868822677099297, 0.95053034165985795, 0.94165806999482904, 0.93207807987612601, 0.92179757130129403, 0.91082427075393002, 0.89916642539671898, 0.88683279687313799, 0.87383265472251104, 0.86017576941332496, 0.84587240500008198, 0.83093331140918203, 0.81536971635963695, 0.79919331692469797, 0.78241627074072795, 0.76505118686993401, 0.74711111632382299, 0.72860954225449404, 0.70956036982116599, 0.68997791573951905, 0.66987689752174295, 0.649272422415344, 0.62817997604904996, 0.60661541079433601, 0.584594933851312, 0.56213509506794002, 0.53925277450172504, 0.51596516973324402, 0.49228978294099801, 0.46824440774739501, 0.44384711584564701, 0.41911624341769299, 0.39407037735334999, 0.36872834128103499, 0.34310918142055002, 0.31723215226859403, 0.291116702127733, 0.26478245848970899, 0.23824921328407, 0.21153690800324301, 0.18466561871516801, 0.157655540974798, 0.130526974645817, 0.10330030864392201, 0.07599600561323, 0.048634586547227202, 0.0212366153658834] // y values (could be repeating)

It is natural to express a binary search as a recursive algorithm - and usually clearer, at least when you are comfortable with recursion. How about this:
func binarySearchHelper <T:Comparable> (array: Array<T>, item:T, lower:Int, upper:Int) -> Int? {
guard lower <= upper else { return nil }
let center = (lower + upper) / 2
return array[center] == item
? center
: ((lower == center ? nil : binarySearchHelper (array: array, item: item, lower: lower, upper: center)) ??
(upper == center + 1 ? nil : binarySearchHelper (array: array, item: item, lower: center + 1, upper: upper)))
}
func binarySearch <T:Comparable> (array: Array<T>, item:T) -> Int? {
return binarySearchHelper (array: array, item: item, lower: array.startIndex, upper: array.endIndex)
}

Use another array which keeps the indexes. Like:
let indexArray = [0, 1, 2, 3, 4]
Then whenever you switch a number in your original array, switch the equivalent values in indexArray.
At the end the index array would be like:
[3, 0, 1, 4, 2]
using this you can easily get the original index.
If you send the code you are using to sort I can change the code and show you how to do it..
Another method:
You can keep a copy of your original array:
let copyArray = a.copy()
then use this to find the index of each value:
let indexOfA = copyArray.index(of: "aValue")
copyArray[indexOfA] = nil
// OR if the values are all positive
copyArray[indexOfA] = -1

Related

Retrieving Values from a Seq based on a condition

I have the below Seq with me
scala> var al = Seq((1.0, 20.0, 100.0), (2.0, 30.0, 100.0), (1.0, 11.0, 100.0), (1.0, 20.0, 100.0), (1.0, 10.0, 100.0),(2.0,9.0,100.0))
al: Seq[(Double, Double, Double)] = List((1.0,20.0,100.0), (2.0,30.0,100.0), (1.0,11.0,100.0), (1.0,20.0,100.0), (1.0,10.0,100.0), (2.0,9.0,100.0))
How to take from this Seq the first n elements where - sum of the second item is greater than 60 percent of the third item(this will be a constant value)
Expected Output -
scala> Seq((1.0, 20.0, 100.0), (2.0, 30.0, 100.0), (1.0, 11.0, 100.0))
res30: Seq[(Double, Double, Double)] = List((1.0,20.0,100.0), (2.0,30.0,100.0), (1.0,11.0,100.0))
Edit -1
I have done this with some ugly way. But if there is any beautiful functional way of solving this would be great. I would really need to get rid of this counters and is little bit tricky for me.
var counter =0d ; var sum = 0d
var abc :Seq[Double] = for (x <- al) yield {
counter+=1 ;sum = sum + x._2 ;
if (sum > 60) counter else 0
}
println(al.take(abc.filterNot(_==0).min.toInt))
If you're on Scala 2.13.x then you might unfold():
Seq.unfold((al,0.0)){ case (lst,sum) =>
Option.when(lst.nonEmpty && sum < 0.6 * lst.head._3) {
(lst.head, (lst.tail, sum + lst.head._2))
}
}
//res0: Seq[(Double, Double, Double)] =
// List((1.0,20.0,100.0), (2.0,30.0,100.0), (1.0,11.0,100.0))
On earlier Scala versions you could scanLeft() to calculate the sums and use that to count how many elements to take().
val cnt = al.view
.scanLeft(0.0)(_ + _._2)
.takeWhile(_ < 0.6 * al.headOption.getOrElse((0d,0d,0d))._3)
.length
al.take(cnt)
You can use recursive function with accumulator to get needed number of elements:
def getIndex(input: Seq[(Double,Double,Double)], index: Int = 0, sum: Double = 0.0): Int = {
input match {
case Seq() => index
case Seq(head, _#_*) if head._2 + sum > head._3 * 0.6 => index + 1
case Seq(head, tail#_*) => getIndex(tail, index + 1, sum + head._2)
}
}
al.take(getIndex(al))
Or to build a list:
def getList(input: Seq[(Double,Double,Double)], sum: Double = 0.0): List[(Double,Double,Double)] = {
input match {
case Seq() => List.empty
case Seq(head, _#_*) if head._2 + sum > head._3 * 0.6 => head :: List.empty
case Seq(head, tail#_*) => head :: get(tail, sum + head._2)
}
}
getList(al)
As mentioned in comments - restricting al to List can allow using :: which should be more efficient:
def get(input: List[(Double,Double,Double)], sum: Double = 0.0): List[(Double,Double,Double)] = {
input match {
case Seq() => List.empty
case head :: tail if head._2 + sum > head._3 * 0.6 => head :: List.empty
case head :: tail => head :: get(tail, sum + head._2)
}
}

Math operations individual elements in 2D Array - Swift

I’m trying to perform different mathematical operations on individual elements of a 2D array (testArray) combined with 1D array (mod). I’ve got the following for generating individual variables but can’t figure out how to get these values back into a new 2D array. Swift 3.0.2.
let testArray: [[Double]] =
[[0,100,20.1],
[1,99,19.2],
[3,98,18.2],
[5,97,17.3],
[7,96,16.4],
[9,95,15.5]]
let mod: [Double] = [0,5,7,14,20,22]
//Math operations on the two above arrays
for var x in 0..<testArray.count {
var result1 = Double(testArray[x][0])
var result2 = Double(testArray[x][1] + mod[x])
var result3 = Double(testArray[x][2] - mod[x])
print(result1,result2,result3)
}
//output is as follows:
0.0 100.0 20.1
1.0 104.0 14.2
3.0 105.0 11.2
5.0 111.0 3.3
7.0 116.0 -3.6
9.0 117.0 -6.5
//how do I get the same numbers into a new 2D array as follows:
[[0.0,100.0,20.1],
[1.0,104.0,14.2],
[3.0,105.0,11.2],
[5.0,111.0,3.3],
[7.0,116.0,-3.6],
[9.0,117.0,-6.5]]
It could be as simple as this,
var anotherArray: [[Double]] = []
for x in 0..<testArray.count {
let result1 = Double(testArray[x][0])
let result2 = Double(testArray[x][1] + mod[x])
let result3 = Double(testArray[x][2] - mod[x])
anotherArray.append([result1, result2, result3])
}
print(anotherArray)
You can use map:
let result = testArray.indices.map { [ testArray[$0][0], testArray[$0][1] + mod[$0], testArray[$0][2] - mod[$0] ] }
On a side note, your for block can be written as:
for x in testArray.indices {
let result1 = testArray[x][0]
let result2 = testArray[x][1] + mod[x]
let result3 = testArray[x][2] - mod[x]
print(result1,result2,result3)
}

Array of size n to array n x 2 using Java 8 stream

I am trying to figure out the most elegant way of converting a simple int array (e.g. {1, 2, 3}) to a simple String array (e.g. {"id", "1", "id", "2", "id", "3"}) of String pairs using Java 8 streams.
Traditionally the code looks like this: -
int[] input = {1, 2, 3};
String[] output = new String[input.length * 2];
int i = 0;
for (int val : input) {
output[i++] = "id";
output[i++] = String.valueOf(val);
}
But assuming this can be done in a 1-liner in Java 8.
String[] result = Arrays.stream(input)
.mapToObj(x -> new String[] { "id", "" + x })
.flatMap(Arrays::stream)
.toArray(String[]::new);
Or may be a bit more verbose (but worse since we are first joining, only to split immediately after)
String[] result = Arrays.stream(input)
.mapToObj(x -> "id" + "," + x)
.collect(Collectors.joining(","))
.split(",");
I can think of these two, but it's hardly more readable of what you already have in place with a simple for loop.
Can make it even less readable than Eugene's solution:
String[] output = IntStream.range(0, input.length * 2)
.mapToObj(x -> x % 2 == 0 ? "id" : input[x / 2 ] + "")
.toArray(String[]::new);
And another variation of this can be next:
String[] result = Arrays.stream( input )
.boxed()
.flatMap( x -> Stream.of( "id", Integer.toString( x ) ) )
.toArray( String[]::new );

Merge random elements of array/split into chunks

How can I split array into chunks with some special algorithm? E.g. I need to shorten array to the size of 10 elements. If I have array of 11 elements, I want two next standing elements get merged. If I have array of 13 elements, I want three elements merged. And so on. Is there any solution?
Sample #1
var test = ['1','2','3','4','5','6','7','8','9','10','11'];
Need result = [['1'],['2'],['3'],['4'],['5|6'],['7'],['8'],['9'],['10'],['11']]
Sample #2
var test = ['1','2','3','4','5','6','7','8','9','10','11','12','13'];
Need result = [['1|2'],['3'],['4'],['5'],['6'],['7|8'],['9'],['10'],['11'],['12|13']]
Thank you in advance.
The following code most probably does what you want.
function condense(a){
var source = a.slice(),
len = a.length,
excessCount = (len - 10) % 10,
step = excessCount - 1 ? Math.floor(10/(excessCount-1)) : 0,
groupSize = Math.floor(len / 10),
template = Array(10).fill()
.map((_,i) => step ? i%step === 0 ? groupSize + 1
: i === 9 ? groupSize + 1
: groupSize
: i === 4 ? groupSize + 1
: groupSize);
return template.map(e => source.splice(0,e)
.reduce((p,c) => p + "|" + c));
}
var test1 = ['1','2','3','4','5','6','7','8','9','10','11'],
test2 = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21'];
console.log(condense(test1));
console.log(condense(test2));
A - Find the difference and create thus many random numbers for merge and put in array
B - loop through initial numbers array.
B1 - if iterator number is in the merge number array (with indexOf), you merge it with the next one and increase iterator (to skip next one as it is merged and already in results array)
B1 example:
int mergers[] = [2, 7, 10]
//in loop when i=2
if (mergers.indexOf(i)>-1) { //true
String newVal = array[i]+"|"+array[i+1]; //will merge 2 and 3 to "2|3"
i++; //adds 1, so i=3. next loop is with i=4
}
C - put new value in results array
You can try this code
jQuery(document).ready(function(){
var test = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'];
var arrays = [];
var checkLength = test.length;
var getFirstSet = test.slice(0,10);
var getOthers = test.slice(10,checkLength);
$.each( getFirstSet, function( key,value ) {
if(key in getOthers){
values = value +'|'+ getOthers[key];
arrays.push(values);
}else{
arrays.push(value);
}
});
console.log(arrays);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

customizable PageRank algorithm in Gremlin?

I'm looking for a Gremlin version of a customizable PageRank algorithm. There are a few old versions out there, one (from: http://www.infoq.com/articles/graph-nosql-neo4j) is pasted below. I'm having trouble fitting the flow into the current GremlinGroovyPipeline-based structure. What is the modernized equivalent of this or something like it?
$_g := tg:open()
g:load('data/graph-example-2.xml')
$m := g:map()
$_ := g:key('type', 'song')[g:rand-nat()]
repeat 2500
$_ := ./outE[#label='followed_by'][g:rand-nat()]/inV
if count($_) > 0
g:op-value('+',$m,$_[1]/#name, 1.0)
end
if g:rand-real() > 0.85 or count($_) = 0
$_ := g:key('type', 'song')[g:rand-nat()]
end
end
g:sort($m,'value',true())
Another version is available on slide 55 of http://www.slideshare.net/slidarko/gremlin-a-graphbased-programming-language-3876581. The ability to use the if statements and change the traversal based on them is valuable for customization.
many thanks
I guess I'll answer it myself in case somebody else needs it. Be warned that this is not a very efficient PageRank calculation. It should only be viewed as a learning example.
g = new TinkerGraph()
g.loadGraphML('graph-example-2.xml')
m = [:]
g.V('type','song').sideEffect{m[it.name] = 0}
// pick a random song node that has 'followed_by' edge
def randnode(g) {
return(g.V('type','song').filter{it.outE('followed_by').hasNext()}.shuffle[0].next())
}
v = randnode(g)
for(i in 0..2500) {
v = v.outE('followed_by').shuffle[0].inV
v = v.hasNext()?v.next():null
if (v != null) {
m[v.name] += 1
}
if ((Math.random() > 0.85) || (v == null)) {
v = randnode(g)
}
}
msum = m.values().sum()
m.each{k,v -> m[k] = v / msum}
println "top 10 songs: (normalized PageRank)"
m.sort {-it.value }[0..10]
Here's a good reference for a simplified one-liner:
https://groups.google.com/forum/m/#!msg/gremlin-users/CRIlDpmBT7g/-tRgszCTOKwJ
(as well as the Gremlin wiki: https://github.com/tinkerpop/gremlin/wiki)

Resources