Given an index, swap array elements accordingly - arrays

What I am trying to achieve is somewhat like a radio group behavior, where only one radio input can be selected at a time. For example, the starting array [0, 1, 1, 1, 1, 1] should have its elements swapped in the following way:
index
array
0
[0, 1, 1, 1, 1, 1]
1
[1, 0, 1, 1, 1, 1]
2
[1, 1, 0, 1, 1, 1]
3
[1, 1, 1, 0, 1, 1]
4
[1, 1, 1, 1, 0, 1]
5
[1, 1, 1, 1, 1, 0]
I have come up with this, but I think it does "extra work" (unnecessary loops) in certain scenarios.
function rearrange(array: number[], idx: number) {
let arr = array.slice();
let l = arr.length;
if (arr.indexOf(0) === idx) return arr;
while (arr.indexOf(0) !== idx) {
let swap;
for (let i = 0; i < l; i++) {
if (arr[i] === 0 || arr[i + 1] === 0) {
swap = arr[i];
if (i + 1 < l) {
arr[i] = arr[i + 1];
arr[i + 1] = swap;
}
if (i + 1 > l) {
arr[i] = arr[i - 1];
arr[i - 1] = swap;
}
}
}
}
return arr;
}
I was wondering if you would have ideas on how to make this process simpler/better.

Just identify the previous 0 with findIndex, assign 1 to it, and assign 0 to the idx?
function rearrange(array: number[], idx: number) {
const arr = [...array];
arr[arr.indexOf(0)] = 1;
arr[idx] = 0;
return arr;
}
Another approach...
const rearrange = (array: number[], idx: number) => (
array.map((_, i) => i === idx ? 0 : 1)
);

Instead of swapping pairs, you can rotate the subarray in "one go", using slice and splice.
Here is a function that does the job, mutating the given array (not returning a new one), together with a sequence of calls to demonstrate it. I assume values could be varying and need to stay together as if they were swapped with the "moving" 0:
function rearrange(array, idx) {
let zero = array.indexOf(0);
if (zero < idx) {
arr.splice(zero, idx - zero + 1, ...arr.slice(zero + 1, idx + 1), 0);
} else {
arr.splice(idx, zero - idx + 1, 0, ...arr.slice(idx, zero));
}
}
arr = [0,1,2,3,4,5];
rearrange(arr, 3);
console.log(...arr);
rearrange(arr, 1);
console.log(...arr);
rearrange(arr, 5);
console.log(...arr);
rearrange(arr, 1);
console.log(...arr);

Related

how do I reduce number of for loops?

let array = [1, 2, 3, 6, 9, 4]
let sumOf = 8
func sumOfArrayFuntion(_ array: [Int], sumOf: Int) -> Bool {
var isTrue = false
for i in 0...array.count-1 {
for j in 0...array.count-1 {
for k in 0...array.count-1 {
if array[i] + array[j] + array[k] == sumOf {
isTrue = true
}
}
}
}
return isTrue
}
sumOfArrayFuntion(array, sumOf: sumOf)
function returns true if any three integers in an array add to sumOf variable, this code is not efficient, more importantly how do I think if being efficient.
Don’t start each loop at zero. You are wasting a lot of time checking invalid combinations. Also stop each loop at the appropriate point. And you can return as soon as you find a match.
I’ve also updated the code to cut down on the number of additions.
let array = [1, 2, 3, 6, 9, 4]
let sumOf = 8
func sumOfArrayFuntion(_ array: [Int], sumOf: Int) -> Bool {
guard array.count >= 3 else { return false }
for i in 0..<array.count-2 {
for j in i+1..<array.count-1 {
let sum = array[i] + array[j]
for k in j+1..<array.count {
if sum + array[k] == sumOf {
return true
}
}
}
}
return false
}
sumOfArrayFuntion(array, sumOf: sumOf)

Find and return the element which occurs most frequently in an array

I need to implement a function called findMode to find the mode of an array. Assuming the array contains integer numbers only. When the function is called and the array is empty it returns 0. When the function is called and the array isn't empty it should return the element which occurs most frequently in an array. If an array contains multiple modes it should return the smallest value of the modes. I need to create an intermediate array, another array of numbers to count the number of times each value occurs. This array should use the index numbers of the array to track of how many times a number in b has been counted.
below is what I have so far:
import { print } from "....";
export let main = async () => {
let input = [2, 1, 1, 2, 1, 0]
print(mode(input))
};
export let findMode = (b: number[]): number => {
let newArr: number[] = []; /** this is the new number array created to store count, this is the intermediate array */
if (b.length === 0) {
return 0;
for (let i = 0; i < b.length; i++) {
};
main();
Here are the expected/actual results:
If the array is b[2,1,1,2,1,0] then 1 should be returned, and if we printed the array we created to store the count it should print newArr[1,3,2] because element 0 has 1 occurrence, element 1 has 3 occurrences, and element 2 has 2 occurrences. The idea is to go from 0 as an element in our input array to it 0 being an index in our intermediate array. so lastly we see which is our max occurrences ( or max element in our intermediate array) which is 3 at index 1, so the mode is 1.
If the array is b[0,0,0,1,1,2,1,1] then 1 should be returned. If the array is b[4,4,7,4,0,7] then 4 should be returned. If the array is b[-4,-4,-1,3,5] then -4 should be returned. If the array is b[1,1,2,3,2] then 1 should be returned since its the smallest of the modes. If the array is b[10,10,10,20,20,30] then 10 should be returned.
Would something like this work?
export let findMode = (b: number[]): number => {
// we'll store the values in b and the number of times they occur here
const counts: Array<{ value: number, count: number }> = [];
// it helps to check that b is defined before you check length, this avoids ReferenceErrors
if (!b || !b.length) {
return 0;
}
for (let i = 0; i < b.length; i++) {
const val = b[i];
const count = counts.find(count => count.value === val);
if (count) {
count.count++;
} else {
counts.push({ value: val, count: 1 });
}
}
// get the mode by sorting counts descending and grabbing the most occuring
const mode = counts.sort((c1, c2) => c2.count - c1.count)[0];
// and now if you *need* an intermediate array with the index mapped to the value and value mapped to the count:
const largestNumber = counts.sort((c1, c2) => c2.value - c1.value)[0];
// initialize an empty as long as the largest number
let newArr = new Array(largestNumber);
newArr = newArr.map((val, i) => {
const count = counts.find(count => count.value === i);
if (count) {
return count.count;
} else {
return 0; // 'i' occurs 0 times in 'b'
}
});
};
You can use Array#reduce method to achieve the result with an additional object for keeping count.
export let findMode = (b: number[]): number => {
// object for keeping count of each element
// initially set `0` with 0 count (default value)
let ref = {
'0': 0
};
return b.reduce((value, num) => {
// define count as 0 if not defined
ref[num] = ref[num] || 0;
// increment element count
ref[num]++;
// if number count is gretater than previous element count
// then return current element
if (ref[num] > ref[value]) {
return num;
// if counts are same then return the smallest value
} else if (ref[num] === ref[value]) {
return num < value ? num : value;
}
// else return the previous value
return value;
// set initial value as 0(default)
}, 0);
};
let findMode = b => {
let ref = {
'0': 0
};
return b.reduce((value, num) => {
ref[num] = ref[num] || 0;
ref[num]++;
if (ref[num] > ref[value]) {
return num;
} else if (ref[num] === ref[value]) {
return num < value ? num : value;
}
return value;
}, 0);
};
[
[2, 1, 1, 2, 1, 0],
[1, 3, 2],
[0, 0, 0, 1, 1, 2, 1, 1],
[4, 4, 7, 4, 0, 7],
[-4, -4, -1, 3, 5],
[1, 1, 2, 3, 2],
[10, 10, 10, 20, 20, 30]
].forEach(v => console.log(findMode(v)))

How to find segments of close values in an array?

How to implement an algorithm that finds segments of continous close values in an array?
Let's say that we start with the following array:
array = [5, 6, 4, 0, 5, 10, 12, 10, 11, 4, 3, 2, 3, 2, 1, 3, 1, 0, 2]
Let's also assume that we will tolerate a "closeness" in each segment of maximum value of 3.
The segments produced would be something like the following:
seg[0] = [5, 6, 4]
seg[1] = [0]
seg[2] = [5]
seg[3] = [10, 12, 10, 11]
seg[4] = [4, 3, 2, 3, 2]
seg[5] = [1, 3, 1]
seg[6] = [0, 2]
Also, we could allow a "dropout" of, say, maximum one continous value that would fall out of the current segment but would be included if the following values fit in the segment. This would produce something like:
seg[0] = [5, 6, 4, 0, 5] //include 0 as a "dropout"
seg[1] = [10, 12, 10, 11]
seg[3] = [4, 3, 2, 3, 2, 1, 3] // include 1 as a "dropout"
seg[4] = [1, 3, 1, 0, 2] // include 0 as a "droput"
Ideas on how to implement such an algorithm?
Here's my own take on it. Written in Haxe (haxe.org).
The checkDropout() method checks for "dropouts" of n length, and "normalizes" them away to an average number of the current segment.
using Lambda;
class Example {
static function main() {
var a:Array<Float> = [5, 6, 4, 0, 5, 10, 12, 10, 11, 4, 3, 2, 3, 2, 1, 3, 1, 0, 2];
// Segment value tolerance of 2
// Dropout max length of 3
var segmentor = new Segmentor(2, 3);
// Callback for displaying result
segmentor.displayResult = (r, v) -> {
trace('-------------------------------------');
trace('value added: ' + v);
trace('result: ' + r);
}
// Feed the segmentor with the example values
a.map(i -> segmentor.addNumber(i));
// var result = [
// [5, 6, 4, 5, 5],
// [10, 12, 10, 11],
// [4, 3, 2, 3, 2],
// [1, 3, 1],
// [0, 2]
// ];
}
}
class Segmentor {
public function new(valueSpan:Int = 2, dropoutLength:Int = 1) {
this.valueSpan = valueSpan;
this.dropoutLength = dropoutLength;
this.result = [];
this.result.push([]);
}
var dropoutLength:Int = null;
var valueSpan:Int = null;
public var result(default, null):Array<Array<Float>>;
public function addNumber(v:Float) {
this.processNumber(v);
}
function processNumber(v:Float) {
var current = this.result[this.result.length - 1];
if (current.length == 0) {
current.push(v);
} else if (fitIn(current, v) || this.checkDropout(v)) {
var current2 = this.result[this.result.length - 1];
current2.push(v);
} else {
this.result.push([v]);
}
this.displayResult(this.result, v);
}
dynamic public function displayResult(result:Array<Array<Float>>, valueAdded:Float) {}
function checkDropout(v:Float):Bool {
if (this.result.length <= 1)
return false;
var last = this.result[this.result.length - 1];
if (last.length <= this.dropoutLength) {
var prev = this.result[this.result.length - 2];
if (fitIn(prev, v)) {
var mid = mid(prev);
var newLast = [for (i in 0...last.length) mid];
newLast.map(n -> prev.push(n));
this.result.pop();
return true;
}
}
return false;
}
function fitIn(a:Array<Float>, v:Float):Bool {
var max = a.fold((c, v) -> Math.max(v, c), a[0]);
var min = a.fold((c, v) -> Math.min(v, c), a[0]);
var fit = ((max - v <= this.valueSpan) && (v - min <= this.valueSpan));
return fit;
}
function mid(a:Array<Float>) {
var max = a.fold((c, v) -> Math.max(v, c), a[0]);
var min = a.fold((c, v) -> Math.min(v, c), a[0]);
return min + (max - min) / 2;
}
}

Looping through Array, return largest number

For the Life of me i can not understand why this doesn't work.
I'm trying to find the Largest number in the array. Plz explain what I did wrong here.
function largestOfFour(arr) {
var maxArry = [];
for (let i = 0; i < arr.length; i++) {
var Max = 0;
for (let y = 0; y < arr.length; y++) {
var currentElement = arr[i][y];
if (currentElement >= Max) {
Max = currentElement;
}
}
console.log(Max);
}
}
largestOfFour([
[4, 5, 6, 7, 9],
[9, 4, 5, 64, 3],
[4, 4, 6, 8, 35],
[3, 5, 76, 54, 3]
]);
Try this:
function largestOfFour(arr) {
var largestNr = 0;
arr.map(child => {
var largestChild = Math.max(...child)
if (largestChild > largestNr) largestNr = largestChild
})
return largestNr;
}
or if you care about IE browser support of Spread opearator, use:
var largestChild = Math.max.apply(null, child)
Array.Map() is more reliable these days because it's easier to use and less bug-prone :)
You can read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Try this for sort array:
var Arr = [1, 7, 2, 8, 3, 4, 5, 0, 9];
for (var i = 1; i < Arr.length; i++)
for (var j = 0; j < i; j++)
if (Arr[i] > Arr[j]) {
var x = Arr[i];
Arr[i] = Arr[j];
Arr[j] = x;
}
console.log(Arr);
then get four first item in array.
Your variable assignment of Max needs to go outside your for loop as every time you finish your inner loop, Max will reset to 0 as you iterate through the outer loop.

Sort array with goal to minimize sequence repeat

Ok so I have an array of websocket client connections. Imagine that this array contains connections to several different machines. Imagine that each different letter (1,2,3, etc) represents a different host. It might look like this:
const conns = [1,1,1,3,3,1,3,2,2,2,2,3,2,1,1,2,2];
what I would like to do, is sort the array like so:
const conns = [1,2,3,1,2,3,1,2,3, ... etc];
the rationale is if a client does not respond, I don't want to retry to the same host, I would like to try sending a message to a client on a different host, and only come back to the original host later. This is basically like a round-robin type thing.
I assume the best way to sort the array like this is:
find all the different hosts (unique letters) in the array
Iterate over this unique list, and splice off items from the original array as I go.
Here is the JS code I have for the above algorithm:
const list = [1,2,3,4,5,1,1,1,1,1,2,3,4,5,1,2,11,3,3,3,3,3,4,4,4,1,1,1];
const _ = require('lodash');
function findAndRemoveFirstMatch(m, list){
for(var i = 0; i < list.length; i++){
if(m === list[i]){
return list.splice(i,1)[0];
}
}
}
function getSorted(list){
const ret = [];
const set = _.uniqBy(list, function(x){
return x;
});
while(list.length > 0){
var i = 0;
while(i < set.length && list.length > 0){
var item;
if(item = findAndRemoveFirstMatch(set[i],list)){
ret.push(item);
}
i++;
}
}
return ret;
}
console.log(getSorted(list));
//given the above input, we get:
[ 1, 2, 3, 4, 5, 11, 1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 3, 4, 1, 3, 4, 1, 3, 1, 3, 1, 1, 1 ]
I am not proud of this code, and am wondering if there is a better way to do it. The above works for this input, but looking for a good way to clean it up and make it more generic.
Is there a better/faster way to do this?
You can do it differently:
sort input - it will help later
find maximum count of equal elements (10 in your example, for element=1), cnt
create cnt buckets to distribute elements over them
put elements in sorted order one by one into next bucket with round-robin principle
merge buckets
This way you get longer series in the end, 1 less than at the beginning.
[1, 2, 4, 1, 2, 4, 1, 2, 4, 1, 3, 4, 1, 3, 4, 1, 3, 5, 1, 3, 5, 1, 3, 11, 1, 3, 1, 3]
Bad case is when one element appears more than n/2 times, but that's unavoidable.
var list = [1,2,3,4,5,1,1,1,1,1,2,3,4,5,1,2,11,3,3,3,3,3,4,4,4,1,1,1];
var a = list.sort(function(a, b) { return a - b; });
var cnt = a.reduce(function(res, cur) {
if (cur == res[0])
return [cur, res[1]+1, Math.max(res[1]+1, res[2])]
else
return [cur, 1, Math.max(1, res[2])];
}, [null, 0, 0])[2];
var buckets = [];
for (var i = 0; i < cnt; i++)
buckets[i] = [];
var j = 0;
for (var i = 0; i < a.length; i++) {
buckets[j].push(a[i]);
j = (j+1)%cnt;
}
var res = buckets.reduce(function(r, cur) {
return r.concat(cur);
});
If you insist on full list of key from beginning, it's also possible:
var list = [1,2,3,4,5,1,1,1,1,1,2,3,4,5,1,2,11,3,3,3,3,3,4,4,4,1,1,1];
var a = list.sort(function(a, b) { return a - b; });
var cnt = a.reduce(function(res, cur) {
if (cur == res[0])
return [cur, res[1]+1, Math.max(res[1]+1, res[2])]
else
return [cur, 1, Math.max(1, res[2])];
}, [null, 0, 0])[2];
var buckets = [];
for (var i = 0; i < cnt; i++)
buckets[i] = [];
var j = 0;
var cur = null;
for (var i = 0; i < a.length; i++) {
if (cur != a[i])
j = 0;
buckets[j].push(a[i]);
j = j+1;
}
var res = buckets.reduce(function(r, cur) {
return r.concat(cur);
});

Resources