It's a simple Vue.js test application and the code looks as following:
<template>
<div>
<button #click="onPrevious">Previous</button>
<button #click="onNext">Next</button>
<br><br>
<div v-for="(a, index) in chunkedArr()" :key="index">
<div v-for="(i, index) in a" :key="index">{{ i }}</div>
-
</div>
</div>
</template>
<script>
export default {
data() {
return {
input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
newInput: [],
currentIndex: 0
}
},
mounted() {
const temp = []
for (let i = 0; i < this.input.length; i += 3) {
let chunk = this.input.slice(i, i + 3)
if (chunk.length === 1) {
chunk = chunk.concat(this.input.slice(0, 2))
}
if (chunk.length === 2) {
chunk = chunk.concat(this.input.slice(0, 1))
}
temp.push(chunk)
}
this.newInput = temp.flat()
},
methods: {
chunkedArr() {
if (this.newInput.length === 0) {
return
}
const output = []
for (let i = this.currentIndex; i < this.newInput.length; i += 3) {
let chunk = this.newInput.slice(i, i + 3)
output.push(chunk)
}
console.log(output)
return output
},
onNext () {
this.chunkedArr()
},
onPrevious () {
// TODO
}
},
}
</script>
We could simulate carousel with Next and Previous buttons. Suppose we have some array of elements that should be displayed in carousel.
But, in this carousel we should display 3 elements at once. It means 3 elements should be visible only on each click Next/Previous. For example, if we have an array of elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, the initial state is to display: 1, 2, 3. On first click on Next, carousel should display 4, 5, 6 and so on. There are 3 cases at the end of array. The array can have 1, 2 or 3 elements at the end. If it has 3 elements, everything is easy. But if it has 1 or 2 elements, we need to add 2 or 1 elements respectively. In case of having 1 element at the end we need to add first 2 elements of array in order to display 3 elements. In case of having 2 elements at the end (our test case) we need to add first element only in order to display 3 elements. The rotating should go further based on previously described scenario.
Please, take a look at the screenshot attached:
In real case I need that data structure for BootstrapVue's Carousel.
UPDATE:
There are 4 subarrays in output array. Please, take a look at the screenshot below:
UPDATE:
const example = [1, 2, 3, 4, 5];
const subArrayIterator = subArrayGenerator(example);
console.log('init: ' + subArrayIterator.next().value); // init
const prevBtn = document.getElementById('prev');
const nextBtn = document.getElementById('next');
prevBtn.onclick = () => {
console.log(subArrayIterator.next(false).value);
}
nextBtn.onclick = () => {
console.log(subArrayIterator.next().value);
}
function* subArrayGenerator(inputArray, subArrayLength=3) {
let prev = false;
for (let i = 0; i < inputArray.length;) {
if (prev) {
let diff = subArrayLength*2;
if (diff > inputArray.length) {
diff = diff % inputArray.length;
}
diff = i - diff;
i = diff < 0 ? inputArray.length + diff : diff;
}
const subArray = [];
for (let j = 0; j < subArrayLength; j++) {
subArray.push(inputArray[i]);
i = i < inputArray.length - 1 ? i + 1 : 0;
}
prev = (yield subArray) === false;
}
}
<button type="button" id="prev">prev</button>
<button type="button" id="next">next</button>
Another approach:
Rotate the array by appending a splice of input from 0 to currentIndex:
input.push(...input.splice(0, currentIndex))
Pad the array to a max length of 12 by appending a slice of input from 0 to the pad length:
while (12 - input.length > 0) {
input.push(...input.slice(0, 12 - input.length))
}
Split the array into slices of 3 by Array(size).fill().map():
const output = Array(Math.ceil(input.length / 3)).fill().map((_, i) => input.slice(i * 3, i * 3 + 3))
demo
Related
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)))
This is the solution I had tried but It was in the order of O(n^2) so didn't passed the test result
func sortArrayByValueAndByFrequency(nums : [Int]) {
var countDict = [Int : Int]()
var count = Int()
var values = Int()
var output = [Int]()
for index in 0 ..< nums.count {
for index2 in 0 ..< nums.count{
if nums[index2] == nums[index] {
values = nums[index2]
count += 1
}
}
countDict[values] = count
count = 0
}
let sortedByKey = countDict.sorted { ($0.key < $1.key)}
let sortedByValue = sortedByKey.sorted { ($0.value < $1.value)}
for (k,v) in sortedByValue {
for _ in 1 ... v {
output.append(k)
}
}
output.forEach { (orderedNumber) in
print(orderedNumber)
}
}
Example input/output:
Example array = [1,1,2,3,4,5,5,6,7,7,7,8,9,9,9,20,25,21,20]
Expected output = [2,3,4,6,8,21,25,1,1,5,5,20,20,7,7,7,9,9,9]
example 2 = [1,2,3,4,4,3,3]
output = [1,2,4,4,3,3,3]
This question was asked to me on HackerRank
First determine the number of occurrences of each value (O(n)),
then sort the values, with the number of occurrences as the
first sort criterion, and the value itself as the second
sort criterion (O(n log(n))). The sorting is conveniently done
with a tuple-comparison (compare Swift - Sort array of objects with multiple criteria):
let array = [1,1,2,3,4,5,5,6,7,7,7,8,9,9,9,20,25,21,20]
let countDict = array.reduce(into: [Int:Int]()) {
$0[$1, default: 0] += 1
}
let sorted = array.sorted(by: {
(countDict[$0]!, $0) < (countDict[$1]!, $1)
})
print(sorted)
// [2, 3, 4, 6, 8, 21, 25, 1, 1, 5, 5, 20, 20, 7, 7, 7, 9, 9, 9]
I am using react-table.js to take data from a form, but I want to be able to delete the data out of the table. The button is working so I know that is attached properly, but I can't seem to get it to delete.
Here is the code
handleDelete = item => {
var newArr = [];
const newState = this.props.documentation;
for (var key in newState) {
if (newState.hasOwnProperty(key)) {
let data = newState[key];
data.id = key;
newArr.push(newState[key]);
}
const sliceArr = newArr.slice();
if (sliceArr.indexOf(item) > -1) {
sliceArr.slice(sliceArr.indexOf(item), 1);
}
console.log('New Array', sliceArr);
this.setState({ data: sliceArr });
}
};
Along with the button I am attaching it to
Cell: row => (
<div>
<button onClick={() => this.handleDelete(row.id)}>Delete</button>
</div>
You're looking for splice rather than slice:
const spliceArr = newArr.slice();
if (spliceArr.indexOf(item) > -1) {
spliceArr.splice(spliceArr.indexOf(item), 1);
}
console.log('New Array', spliceArr);
this.setState({ data: spliceArr });
Example:
const newArr = [1, 2, 3, 4]
// [1, 2, 3, 4] example
const spliceArr = newArr.slice()
// [1, 2, 3, 4] ok
spliceArr.slice(spliceArr.indexOf(3), 1)
spliceArr
// [1, 2, 3, 4] oops
spliceArr.splice(spliceArr.indexOf(3), 1)
spliceArr
// [1, 2, 4] better
If that doesn't get you all the way there, you may want to update your question with the rendering (presumably JSX) of the table itself, as #MichaelBenin suggested.
Suppose I have an array arr with several elements. I want to create an array of groups of elements of arr (array of arrays), in which each group is composed of the next element that matched some condition fn and every next element in sequence until the next match.
So I want to kinda slice the array in groups starting by matching elements.
I made the following code to do it, but it's too imperative to me:
var sliceGroupingBy = (arr, fn) => {
var newArray = [];
arr.forEach(el => {
if (fn(el)) {
newArray.push([el]);
} else {
newArray.slice(-1)[0].push(el);
}
});
return newArray;
};
Example:
var in = [1, 2, 4, 6, 3, 4, 6, 5, 7, 8, 8, 1];
var out = sortaGroupBy(in, x => x % 2 === 1);
// [ [ 1, 2, 4, 6 ], [ 3, 4, 6 ], [ 5 ], [ 7, 8, 8 ], [ 1 ] ]
I wonder what's the more functional way to do it, using the regular functional operations only (no if or aux. array).
You can always make it more functional by using reduce instead of some imperative looping:
function sliceGroupingBy(arr, fn) {
return arr.reduce((newArray, el) => {
if (fn(el))
newArray.push([el]);
else
newArray[newArray.length-1].push(el);
return newArray;
}, []);
}
If you also want to avoid the push and, for whatever reasons, statements at all, you can concat:
const sliceGroupingBy = (arr, fn) =>
arr.reduce((newArray, el) =>
fn(el)
? newArray.concat([[el]]);
: newArray.slice(0, -1).concat(newArray.slice(-1).map(lastArray =>
lastArray.concat([el])
)
, []);
("altering" the last element of the array could be done in a myriad of ways)
Grossly inefficient but:
let predicate = x => x % 2 === 1;
let partition = (pred, arr) => {
let res1 = arr.filter(pred);
let res2 = arr.filter(x => !pred(x));
return [res1, res2];
};
partition(predicate, [1,2,3,...]);
I'd never do it that way in JavaScript though (assume from the code that's the language in question). See my comments on your question.
EDIT
Per the comment that I was wrong about what you're doing,
let xs = array.reduce((acc, x, i, arr) => {
let lastIndex = acc.reduce((y, z) => { y + z.length }, 0);
return predicate(x) || i === arr.length - 1 ?
acc.concat([arr.slice(lastIndex, i)]) :
acc;
}, []);
Uses no statements, only expressions, no mutation, only copying. I still wouldn't do this without using immutable.js or mori. Its rather expensive.
EDIT 2
More efficient version of the last approach based on comment from Bergi:
let {result} = array.reduce((obj, x, i, arr) => {
let {lastIndex, result} = obj;
let passes = predicate(x) || i === arr.length - 1;
return {
lastIndex: passes ? i : lastIndex,
result: passes ? result.concat([arr.slice(lastIndex, i)]) : result
};
}, { lastIndex: 0, result: [] });
I have a list of items say items = [1,2,3,4,5,6,7,8, ... ,40].
I am displaying these items using ng-repeat.
challenge is to display them in different divs based on the row count per column.
It should be displayed as
1 4 7
2 5 8
3 6 9
And so on. (if the row count is 3)
==============
1 5 9
2 6 10
3 7 11
4 8 12
And so on (if the row count is 4).
Each column should be in a separate div
for example:
data is
scope. allItems =
[{value = "apple" , id = 1},
{value = "mango" , id = 2},
{value = "banana" , id = 3},
{value = "grapes" , id = 4}]
so on till id = 40
and i am looping using ng-repeat
now all the fruits are coming in single div
apple
mango
banana
grapes
but i want it to be divided into 5 fruits per division
first 5 fruits in one div and another 5 in another div and os on.
You can create a filter to reorder the items in columns.
http://jsbin.com/vinohusoba/edit?html,js,output
<span ng-repeat="item in items | columns:3">
{{item}}
<br ng-if="($index+1) % 3 === 0"/>
</span>
Filter:
var app = angular.module('app', []);
app.controller('MyController', function($scope) {
$scope.items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
});
app.filter('columns', function() {
return function(items, colCount) {
var returnItems = [];
var rows = Math.ceil(items.length / colCount);
var cols = [];
var currentCol = [];
for(var i = 0; i < items.length; i++) {
currentCol.push(items[i]);
if((i+1)%rows === 0) {
cols.push(currentCol);
currentCol = [];
}
}
for(var i = 0; i < rows; i++) {
for(var k = 0; k < colCount; k++) {
returnItems.push(cols[k][i]);
}
}
return returnItems;
};
});
How to style this- you'l have to figure that one out.