Refactor variables in redux functions - javascript

I have to refactor my redux functions
In these 3 cases in am renaming the variable in a different way and i do not want this
See the example
case 'INCREMENT_LIKES' :
const index = action.index;
return [
...state.slice(0,index), // before the one we are updating
{...state[index], likes: state[index].likes + 1},
...state.slice(index + 1), // after the one we are updating
]
case 'INCREMENT_COORDINATES' :
const a = action.index;
let string = state[a].d || state[a].d2;
let array = string.split(" ");
let max = array.length;
let last = max - 2;
let i = (state[a].index || 3) + 1;
if ( i === last ) i = 3;
if (array[i] !== 'M' && array[i] !== 'L') array[i] = parseInt(array[i]) + 20;
return [
...state.slice(0,a), // before the one we are updating
{...state[a], d: array.join(' '), index: i, d2: array.join(' '), index: i }, // updating
...state.slice(a + 1), // after the one we are updating
]
case 'INCREMENT_VIEWBOX' :
const count = action.index;
let string2 = state[count].viewBox;
let array2 = string2.split(" ");
let max2 = array2.length;
let i2 = (state[count].index || 2) + 1;
if ( i2 === max2 ) i2 = 2;
array2[i2] = parseInt(array2[i2]) - 20;
return [
...state.slice(0,count), // before the one we are updating
{...state[count], viewBox: array2.join(' '), index: i2},
...state.slice(count + 1), // after the one we are updating
]
default:
return state;
These are the different variable names in the 3 cases
const index = action.index;
const a = action.index;
const count = action.index;
Same for
let string = state[a].d || state[a].d2;
let string2 = state[count].viewBox;
and
let array = string.split(" ");
let array2 = string2.split(" ");
How can i reuse the same variable name for all the 3 cases?
I mean using the same name for the 3 different cases like:
const index - let string - let array

You can add a scope to each case by wrapping them in curly brackets:
case 'INCREMENT_LIKES' : {
const index = action.index;
return [
...state.slice(0,index), // before the one we are updating
{...state[index], likes: state[index].likes + 1},
...state.slice(index + 1), // after the one we are updating
]
}
case 'SOME_OTHER_ACTION_TYPE' : {
console.log(index) // -> undefined
}

Related

Prioritizing array values

There are 3 empty arrays (a, b, c) and another array (d) with some dynamic values. I need to pass the array values to 'a','b' and 'c' arrays as in the below pattern;
Rather than having seperate IF statements is there a way to write it simpler?
const arrayA = [];
const arrayB = [];
const arrayC = [];
const arrays = [arrayA, arrayB, arrayC];
const arrayD = ['some', 'values', 'here'];
if(arrayD.length <= 3) {
for(i=0; i<3; i++){
arrayA.push(arrays[i][i]);
}
}
EDIT! in my first version I misunderstood the question
This is one way to do it, if I understood your question correctly
const arrayA = [];
const arrayB = [];
const arrayC = [];
const arrays = [arrayA, arrayB, arrayC];
const arrayD = [1, 2, 3, 4, 5, 6, 7];
function myArray(arr) {
let temp = [
[],
[],
[]
]
if (arrayD.length <= 3) {
for (let i = 0; i < arrayD.length; i = i + 3) {
temp[0].push(arrayD[i]);
arrayD[i + 1] === undefined ? null : temp.push(arrayD[i + 1])
arrayD[i + 2] === undefined ? null : temp.push(arrayD[i + 2])
arrayA.push(temp[0])
}
} else {
let index = 0
for (let i = 0; i < arrayD.length; i = i + 3) {
arrayD[i] === undefined ? null :
temp[index].push(arrayD[i])
arrayD[i + 1] === undefined ? null : temp[index].push(arrayD[i + 1]);
arrayD[i + 2] === undefined ? null : temp[index].push(arrayD[i + 2])
index++
}
arrayA.push(...temp[0])
arrayB.push(...temp[1])
arrayC.push(...temp[2])
}
arrays.push[arrayA, arrayB, arrayC]
}
myArray(arrayD)
console.log(arrays)
The problem is simplified if we can calculate the lengths of the output arrays. These are shown in the snippet as al and bl. The third length will be the remainder after slicing away the first two. With that...
const input = [1,2,3,4,5,6,7,8];
let length = input.length;
let al = Math.ceil(length / 3);
let bl = Math.ceil((length - al )/ 2);
let a = input.slice(0, al);
let b = input.slice(al, al+bl);
let c = input.slice(al+bl);
console.log([a, b, c])

How can i rename elements before to insert it?

I want to add the elements of my new list (newList) to my already existing list (oldList), but before inserting I must verify if my element of my newList already exists in my oldList, in case it does, an extra number must be added.
let newList = [{name: "abc.jpeg"}, {name: "abc.jpeg"}]
let oldList = [{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa1.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa2.jpeg"}]
const addElement = (colection, new_item, tally) => {
const a = new_item.name.split('.')
const reps = colection.filter(elem => {
var reg = /.*2Fpictures%2F(.*)/
const name = elem.name.match(reg)
if(name)
return name[1].includes(a[0])
}).length
new_item.sname = a[0] + (reps > 0 ? reps : '') + '.' + a[1]
colection.push(new_item)
console.log(colection)
return colection
}
let tally = {}
for (let index = 0; index < newList.length; index++) {
oldList = addElement(oldList, newList[index], tally)
}
the expected result I need is this:
[{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa1.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa2.jpeg"},
{name: "abc.jpeg"},
{name: "abc1.jpeg"}]
because the three element contain "fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fabc.jpeg" the abc.jpeg
Another approach using what you started with a tally that is a Map and is far more efficient for lookups than using multiple instances of filter()
let newList = [{name: "abc.jpeg"}, {name: "abc.jpeg"},{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa.jpeg"}]
let oldList = [{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa1.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa2.jpeg"}, {name: "abc.jpeg"}];
const baseName = (str) => str.replace(/\d+\./, '.');
const getNamesCount = arr => arr.reduce((a,{name})=>{
const base = baseName(name);
return a.set(base, (a.get(base)||0)+1)
},new Map())
const mergeLists = (oList, nList) => {
const tally = getNamesCount(oList);
nList.forEach(({name,...rest})=>{
const base = baseName(name);
if(tally.has(base)){
let count = tally.get(base)
name = name.split('.').join(count + '.');
tally.set(base, ++count)
}else{
tally.set(base, 1)
}
oList.push({name,...rest})
})
return oList;
}
console.log(mergeLists(oldList,newList))
//I added some element for testing
let newList = [
{name: "abc.jpeg"},
{name: "abc.jpeg"},
{name:"xxx123.jpg"},
{name:"xxx123.jpg"},
{name:"xxx123.jpg"},
{name:"xxx123.jpg"},
{name:"yyy143.jpg"},
{name:"yyy143.jpg"},
{name:"yyy143.jpg"},
{name:"yyy144.jpg"},
{name:"yyy145.jpg"},
{name:"yyy146.jpg"}
];
let oldList = [
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa1.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa2.jpeg"}];
//Creating a Set
const mySet = new Set()
//Fill mySet with files names
for (i=0;i<oldList.length;i++){
mySet.add(oldList[i].name);
}
//Looping newList
for (i=0;i<newList.length;i++){
if (mySet.has(newList[i].name)){
// The point "." position in filename string
pointpos = newList[i].name.lastIndexOf(".");
// File name and file extension
name = newList[i].name.substring(0,pointpos);
ext = newList[i].name.substring(pointpos);
// Getting numbers in file name string from right to left
// initializing cursor pos at the end of the file name string
pos=name.length-1;
//Where to store the numbers of the file name , if any .
numbers=[];
// String numbers 0,1,2,3,4,5,6,7,8,9
// have char codes from 48 to 57
while ( 48 <= name.charCodeAt(pos) && 57 >= name.charCodeAt(pos) && pos >= 0){
//Add values at top of the array , not at bottom.
numbers.unshift(name.charAt(pos));
pos--;
}
//if file name has numbers...
if (numbers.length > 0){
//join numbers and sum 1
num = parseInt(numbers.join(""))+1;
snum = String(num);
// name without numbers part
name = name.substring(0,name.length-numbers.length);
//Sum 1 again while we have a filename in the Set
while (mySet.has(name+snum+ext)){
snum=String(num++);
}
//Here we have a new file name not present in the Set
//So add it to the Set with number and extension
mySet.add( name+snum+ext);
}else{
//The file name is duplicate but
//there are no others with numbers
//so add "1" string to the name and extension
//and add it to the Set
name+="1";
mySet.add(name+ext);
}
}else{
// The filename is not present in oldlist so we can add it in the Set
mySet.add(newList[i].name);
}
}
//Reset oldList array
oldList=[];
//Fill it with objects like it was but with new set items as values
for (let item of mySet) {
oldList.push({name:item})
}
//Show it
console.log(oldList);
Without comments:
const mySet = new Set();
for (i=0;i<oldList.length;i++)mySet.add(oldList[i].name);
for (i=0;i<newList.length;i++){
if (mySet.has(newList[i].name)){
pointpos = newList[i].name.lastIndexOf(".");
name = newList[i].name.substring(0,pointpos);
ext = newList[i].name.substring(pointpos);
pos=name.length-1;
numbers=[];
while ( 48 <= name.charCodeAt(pos) && 57 >= name.charCodeAt(pos) && pos >= 0){
numbers.unshift(name.charAt(pos));
pos--;
}
if (numbers.length > 0){
num = parseInt(numbers.join(""))+1;
snum = String(num);
name = name.substring(0,name.length-numbers.length);
while (mySet.has(name+snum+ext)){
snum=String(num++);
}
mySet.add( name+snum+ext);
}else{
name+="1";
mySet.add(name+ext);
}
}else{
mySet.add(newList[i].name);
}
}
oldList=[];
for (let item of mySet) {
oldList.push({name:item})
}
console.log(oldList);
You can find occurence of the string initially and then append that number to the string.
let newList = [{name: "abc1.jpeg"}, {name: "abc1.jpeg"}]
let oldList = [{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa1.jpeg"},
{name:"fs%2FPanel%8SmgM7rhJ4T9j%2Fpictures%2Fa2.jpeg"}]
const addElement = (colection, new_item, tally) => {
const a = new_item.name.split('.')
const occurence = colection.filter(item=>item.name===new_item.name).length;
if(occurence>0){
const firstPart =[...a.slice(0,-1)].join(".");
const digitMatch = firstPart.match(/(\d+)$/);
const digitString = digitMatch && digitMatch[0];
const firstPartWithoutDigit =digitString && firstPart.slice(0,-digitString.length )
const digit = digitString && parseInt(digitString);
const newDigit = (digit || 0) + occurence;
const prefix = firstPartWithoutDigit || firstPart;
new_item.name = prefix+ newDigit +"." +a[a.length-1]
//[...a.slice(0,-1)].join(".") -> Part Before Last .
// occurence-> Number of times filename exists in the collection
//a[a.length-1] -> Last part of string after .
}
const reps = colection.filter(elem => {
var reg = /.*2Fpictures%2F(.*)/
const name = elem.name.match(reg)
if(name)
return name[1].includes(a[0])
}).length
new_item.sname = a[0] + (reps > 0 ? reps : '') + '.' + a[1]
colection.push(new_item)
console.log(colection)
return colection
}
let tally = {}
for (let index = 0; index < newList.length; index++) {
oldList = addElement(oldList, newList[index], tally)
}

How to remove all next elements from array in javascript or lodash

I have an array of object [{a:1},{a:2},{a:3},{a:4},{a:5}].
I want to find index of {a:3} and remove all next elements from index of {a:3}.
Result should look like [{a:1},{a:2},{a:3}] and removed elements will be {a:4},{a:5}.
You can use Array#findIndex() to find that object by its number, or Array#indexOf() if you have a reference to it.
Then, you can either set the array's length (mutating) or use Array#slice() (not mutating), to reduce its length:
const array = [{a:1},{a:2},{a:3},{a:4},{a:5}]
const i = array.findIndex(({a}) => a === 3)
const arrayCopy = array.slice(0, i + 1)
//or:
array.length = i + 1
console.log(i)
console.log(arrayCopy)
console.log(array)
Or with Array#indexOf():
//If you have a reference from somewhere:
const ref = {a:3}
const array = [{a:1},{a:2},ref,{a:4},{a:5}]
const i = array.indexOf(ref)
const arrayCopy = array.slice(0, i + 1)
//or:
array.length = i + 1
console.log(i)
console.log(arrayCopy)
console.log(array)
Alternatively, if you don't have a reference, but it's guaranteed that the array is sorted, you can use a binary search, that makes this much faster for large arrays:
function binarySearch(array, target, cb) {
let start = 0, end = array.length
while(start < end){
const middle = ((end - start - 1) >>> 1) + start
const middleVal = cb(array[middle], middle)
if(middleVal === target) return middle
if(middleVal < target)
start = middle + 1
else
end = middle
}
return -1
};
const array = [{a:1},{a:2},{a:3},{a:4},{a:5}]
const i = binarySearch(array, 3, ({a}) => a)
const arrayCopy = array.slice(0, i + 1)
//or:
array.length = i + 1
console.log(i)
console.log(arrayCopy)
console.log(array)
One line vanilla JS with slice and findIndex
const data = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }];
const res = data.slice(
0,
data.findIndex((el) => JSON.stringify(el) === JSON.stringify({ a: 3 })) + 1
);
console.log(res);

Creating various arrays from a string using LOOPS

I have a string of values
"000111111122222223333333444455556666"
How could I use a loop to produce one array for index values from 0 to 3 (create an array of [000] and then another array of index values from 3 to 10, 10 to 17, 17 to 24, producing eg. [1111111, 2222222, 333333] and then another loop to produce an array of index values from 24 to 28, 28 to 32, 32 to 36, producing eg. [4444, 5555, 6666])?
So in total 3 different arrays have been created using three different for loops.
array1 = [000]
array2 = [1111111, 2222222, 333333]
array3 = [4444, 5555, 6666]
You may wish to try something line this (only a schematic solution!):
var l_Input = "000111111122222223333333444455556666" ;
var l_Array_1 = [] ;
var l_Array_2 = [] ;
var l_Array_3 = [] ;
var l_One_Char ;
for (var i = 0 ; i < l_Input.length ; i++) {
l_One_Char = l_Input.substring(i,i) ;
if (i < 3) {
l_Array_1.push(l_One_Char) ;
continue ;
}
if (i >= 3 && i < 10) {
l_Array_2.push(l_One_Char) ;
continue ;
}
:
:
}
I think this would work.
const str = '000111111122222223333333444455556666';
function makeArr(str, item) {
let firstIndex = str.indexOf(item);
let lastIndex = str.lastIndexOf(item) + 1;
return [ str.substring(firstIndex, lastIndex) ];
}
const first = makeArr(str, 0);
const second = [].concat(makeArr(str, 1))
.concat(makeArr(str, 2))
.concat(makeArr(str, 3));
const third = [].concat(makeArr(str, 4))
.concat(makeArr(str, 3))
.concat(makeArr(str, 3));
You could map the sub strings.
var str = '000111111122222223333333444455556666',
parts = [[3], [7, 7, 7], [4, 4, 4]],
result = parts.map((i => a => a.map(l => str.slice(i, i += l)))(0));
console.log(result);
function split(string, start, end) {
var result = [],
substring = string[start],
split;
for (var i = start + 1; i < end; i++) {
var char = string[i];
if (char === substring[0])
substring += char;
else {
result.push(substring);
substring = char;
}
}
result.push(substring);
return result;
}
split("00011122",0,8)
["000", "111", "22"]
To do this dynamically, you can use .split() and .map() methods to make an array from your string then group this array items by value.
This is how should be our code:
const str = "000111111122222223333333444455556666";
var groupArrayByValues = function(arr) {
return arr.reduce(function(a, x) {
(a[x] = a[x] || []).push(x);
return a;
}, []);
};
var arr = str.split("").map(v => +v);
var result = groupArrayByValues(arr);
This will give you an array of separate arrays with similar values each.
Demo:
const str = "000111111122222223333333444455556666";
var groupArrayByValues = function(arr) {
return arr.reduce(function(a, x) {
(a[x] = a[x] || []).push(x);
return a;
}, []);
};
var arr = str.split("").map(v => +v);
var result = groupArrayByValues(arr);
console.log(result);

Assign integers from dictionary values to characters of a string

indices and for value in nicely gives me the loop I'm looking for however I need to go a step further and assign the values of the dictionary to the matching characters of the string then perform calculation for score.
I'd like to know the most Swifty way to accomplish this. Is this possible using map? let curChar = n.map({ print($0) }).
The other issue is that Javascript lets you used heterogeneous dictionaries of type easily but with Swift we need to match types.
var dict: [String:Any] = ["a":1, "j":1, "s":1, "b":2, "k":2,"r":9/*...*/]
let n = "lighthouse"
var nScore = 0
for i in n.indices[n.startIndex..<n.endIndex] {
let curChar = n[i]
var curVal = dict[curChar]
nScore = nScore + curVal
The original Javascript block.
var dict = {A:1, J:1, S:1, B:2, K:2, T:2...};
var n = "lighthouse";
var nScore = 0;
for( var i = 0; i < n.length; i++ );
{
var curChar = n.charAt( i );
var curVal = dict[ curChar ];
nScore = nScore + curVal;
}
n[i] is of type Character, so that should be the key type
of the dictionary instead of String. The value type should be Int:
let dict: [Character: Int] = ["a": 1, "j": 1, "s": 1, "b": 2, "k": 2, "r": 9 /* ... */]
You also have to define a "default value" which is used as score
for characters not found in the dictionary, this can be done
with the nil-coalescing operator ??:
let n = "lighthouse"
var nScore = 0
for i in n.indices[n.startIndex..<n.endIndex] {
let curChar = n[i]
let curVal = dict[curChar] ?? 0
nScore = nScore + curVal
}
Or simpler, by enumerating the characters of the string directly:
for c in n {
let curVal = dict[c] ?? 0
nScore = nScore + curVal
}
Even shorter with reduce():
let n = "lighthouse"
let nScore = n.reduce(0) { (score, c) in
score + (dict[c] ?? 0)
}
which can be written more compactly using "shorthand parameters":
let n = "lighthouse"
let nScore = n.reduce(0) { $0 + (dict[$1] ?? 0) }
If it you have full control over the possible characters which can
occur in the input string, and it is guaranteed(!) the dictionary
defines values for all of them then you can force-unwrap the dictionary lookup, for example
let n = "lighthouse"
let nScore = n.reduce(0) { $0 + dict[$1]! }
But this will crash at runtime if a character is not found.
If you define a function
func numericScore(_ str: String) -> Int {
return str.reduce(0) { $0 + (dict[$1] ?? 0) }
}
then you can easily apply it to a single string
let nScore = numericScore("lighthouse")
or map it over an array of strings
let words = ["lighthouse", "motorcycle"]
let scores = words.map(numericScore)
or compute the total score for an array of strings (using reduce again):
let words = ["lighthouse", "motorcycle"]
let totalScore = words.reduce(0) { $0 + numericScore($1) }
// Alternatively in two steps:
let scores = words.map(numericScore)
let totalScores = scores.reduce(0, +)

Categories

Resources