A reversible JavaScript function that swaps three items

Initially, I was tasked with creating a function that could either append the first color in an array to the end or reverse the order of colors. This is the function I created:

// Obtain the colors from scope
var colours = scope.colours;

// Create the swap function
scope.swap = function (opposite) {

    // If we want to reverse the order
    if (opposite) {

        // Reverse the array
        colours.unshift(colours.pop());

    // Else
    } else {

        // Shift the array
        colours.push(colours.shift());
    }
};

Everything was working fine until my client presented me with a more complex challenge and I am wondering if there is an easy way to achieve this.

The client provided a table resembling this:


| C1 | C2 | C3 |

| C2 | C1 | C3 |

| C1 | C3 | C2 |

| C2 | C3 | C1 |

The requirement is:

  • C3 can only be in positions 2 and 3
  • C2 and C1 can occupy any position

Before diving into it, does anyone have suggestions for simplifying this?

Potential Solution

Despite considering other alternatives, I decided to attempt solving it myself. Here's what I came up with:

// Get the colors from scope
var colours = scope.colours;

// Define variables
counter = 2;

// Create the swap function
scope.swap = function (opposite) {

    switch (counter) {
        case 3:

            // Retrieve colors
            var colour2 = colours.shift();
            var colour3 = colours.shift();

            // Rearrange them
            colours.splice(1, 0, colour2);
            colours.splice(2, 0, colour3);

            break;

        case 1:

            // Retrieve colors
            var colour2 = colours.shift();
            var colour1 = colours.shift();

            // Rearrange them
            colours.splice(0, 0, colour1);
            colours.splice(2, 0, colour2);

            break;
        case 0:

            // Retrieve colors
            var colour1 = colours.shift();
            var colour3 = colours.shift();

            // Rearrange them
            colours.splice(1, 0, colour3);
            colours.splice(2, 0, colour1);

            break;
        default:

            // Remove and store the first color value
            var colour1 = colours.shift();

            // Add the color to the second position in the array
            colours.splice(1, 0, colour1);

            break;
    }

    counter--;

    if (counter < 0) {

        counter = 3;
    }
};

This approach functions well, but how can I extend it to work in the opposite direction? For instance, increasing the counter rather than decreasing it (and resetting to 0 when exceeding 3).

Answer №1

If you're dealing with just four different permutations, it's best to simply hardcode them. There's no need to overcomplicate things with complex logic that may need to be revised later if your customer changes their mind.

var color1 = '#ff0000',
    color2 = '#00ff00',
    color3 = '#0000ff',
    permutations = [
        [color1, color2, color3],
        [color2, color1, color3],
        [color1, color3, color2],
        [color2, color3, color1]
    ],
    currentPermIndex = 0;

function switchPerm() {
    currentPermIndex = (currentPermIndex + 1) % 4;
}

function reverseSwitch() {
    // the following method does not work, as explained in the edit
    currentPermIndex = (currentPermIndex - 1) % 4;
}

Example of how to use this: http://jsfiddle.net/acasaccia/qy56x8o0/

[EDIT]: In Javascript, there is a limitation with treating negative numbers for the mod operation. To address this, we must create a polyfill for mod until a proposed solution like this is implemented and utilize it instead of %:

Number.prototype.mod = function(n) {
    return (((this)%n)+n)%n;
}
function switchPerm() {
    currentPermIndex = (currentPermIndex + 1).mod(4);
}

function reverseSwitch() {
    currentPermIndex = (currentPermIndex - 1).mod(4);
}

Answer №2

I have crafted a function that could be of assistance to you. It is designed to work seamlessly with any client combination:

Function Definition

function calculatePosition(colorArr, element, fixedPositionArr) {
    var result = [], usedElement = [];
    var permutationArr = (function recursive() {
        for (var i = 0; i < colorArr.length; i++) {
            var ch = colorArr.splice(i, 1)[0];
            usedElement.push(ch);
            if (colorArr.length == 0) {
                result.push(usedElement.slice());
            }
            recursive();
            colorArr.splice(i, 0, ch);
            usedElement.pop();
        }
        return result;
    })();


    return permutationArr.filter(function(arr){
        var elementPos = parseInt(arr.indexOf(element));
        if(fixedPositionArr.indexOf(elementPos) > -1) return true;

    })
}

Function Call with Three Elements

var colors = new Array('c1', 'c2', 'c3');
var fixedPositionArr = [1, 2];

var resThreeElements = calculatePosition(colors, 'c3', fixedPositionArr)
console.log(resThreeElements);

Function Call with Four Elements

var colors = new Array('c1', 'c2', 'c3', 'c4');
var fixedPositionArr = [2, 3];

var resFourElements = calculatePosition(colors, 'c4', fixedPositionArr)
console.log(resFourElements);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue- async function results in a Promise object with a status of <pending>

Hey everyone, I could use some assistance with my Vue code. Here's the issue: I'm attempting to retrieve data (specifically anime) from an online anime API. In my project, I have two files: Anime.vue (the view page) and getAnime.js (which house ...

How can we process the incoming data that is in a JSON format?

I'm in the process of creating a Zap that collects customer feedback through Unbird and delivers a coherent Slack message that can be easily understood by anyone within my organization. When importing customer feedback data from Unbird into Zapier, i ...

Update the content of the document element by assigning it a lengthy string

I'm utilizing JQuery to dynamically assign content to a div element. The content has numerous lines with specific spacing, so this is the approach I am taking: document.getElementById('body').innerHTML = "Front-End Developer: A <br/> ...

Creating Conditional Vue Components

I am looking to dynamically create a list of actions, each of which is a component, based on a condition where the object variable store.plan is not empty. I attempted using v-if, which worked well for rendering but not for creating the component. However ...

The Click Event is failing to trigger for a dynamically created ID within a span element

I am currently working on a Task Project. In this project, I have been adding items dynamically and generating items dynamically as well. However, when it comes to deleting items by clicking on a span element, the click event doesn't seem to work. I ...

Bring in SASS variables to enhance Material UI theme in NextJS

Within my project, I currently have the following two files: materialTheme.ts import { createMuiTheme, Theme } from "@material-ui/core/styles"; const theme: Theme = createMuiTheme({ palette: { primary: { main: "#209dd2", contras ...

A tutorial on how to switch classes between two tabs with a click event in Vue.js

I am having an issue with my spans. I want to implement a feature where clicking on one tab changes its color to red while the other remains gray. I have tried using class binding in my logic but it's not working. How can I solve this problem and make ...

When refreshing, the useEffect async function will not execute

Upon page load, the getImages function is intended to run only once. After refreshing the page, both tempQuestionImages and questionImages are empty. However, everything works perfectly after a hot reload. I am utilizing nextJs along with Firebase Cloud ...

I seem to be encountering an issue with storing data properly within the for loop - can anyone point out where I may

Within my code, I am iterating through results.data.data.length and successfully retrieving the correct data while storing it appropriately. The data: param1 = [6, 27, 34, 22, 23, 25, 28, 24, 26, 30, 29] // => array length 11 The issue arises when att ...

Semantic-release failing to generate a new version update for package

I'm in the process of setting up semantic release for my NPM package to automate deployment with version updates. However, after migrating from an old repo/npm package to a new one, I'm facing issues with semantic versioning not creating a new re ...

AngularJS mouse event is triggered repetitively within a loop

My goal is to activate the function setHighlight when a li element is hovered over with a mouse. The ng-mouseover event is employed within an ng-repeat loop. The problem arises when hovering over a li element: the ng-mouseover event gets triggered multipl ...

React file viewer failing to display content via Firebase storage URLs

This code snippet is designed to display PDF files uploaded to Firebase storage using React. Here is a sample of the code: import ReactDOM from "react-dom"; import FileViewer from "react-file-viewer"; import "./styles.css"; ...

Need help with resetting a value in an array when a button is clicked?

Using Tabulator to create a table, where clicking on a cell pushes the cell values to an array with initial value of '0'. The goal is to add a reset button that sets the values back to '0' when clicked. component.ts names = [{name: f ...

Tips for changing the state of a parent DOM element from a child component several levels deep in a React application

I am currently incorporating both react-router-dom and Material-UI into my application. Below is a basic example I have created using the following files: routes.tsx import { Outlet, createBrowserRouter } from "react-router-dom" const App = () ...

Using percentages to position Div elements

Currently, I am working on an HTML page that requires a div element spanning the full width of the page. My goal is to arrange other divs within this full-width div using percentages rather than pixels. The class associated with this div is .question. Thi ...

Dealing with a socket.io CORS problem

After deciding to implement a websocket on my website, I opted to utilize the socket.io library. However, I've encountered a CORS error: Access to XMLHttpRequest at 'http://localhost:2021/socket.io/?EIO=4&transport=polling&t=NlbFGS2&apos ...

Incorporating an NPM JavaScript library into Laravel version 8

I've integrated the mobiscroll javascript component library into my new Laravel 8 app by adding the minified css/js files to the public/css and public/js directories. However, I'd like to find a more seamless way to include these components by us ...

Exploring the application of styles within the shadow DOM

I'm experimenting with applying styles to the shadow DOM. Consider the following example: const element = document.getElementById("bar"); const shadowRoot = element.attachShadow({ mode: "open" }); const greeting = document.createElement("p"); gree ...

Error message in JQuery Ajax: "Invalid request to web service, parameter value for 'Object' is missing"

I'm struggling to successfully post a form to my web service. Before sending it to the server, I am converting the form into an object. However, I encounter an error when trying to post the form as an Object to my Asmx web service. Here is my Ajax co ...

Ensure that a sprite object is constantly positioned in front of a skydome object within THREE.js

Currently, I have implemented a custom shader to draw a gradient on a skydome and now I want to include a sun/moon in front of the skydome as well (from the user's perspective). The simplest solution would be to use sprites for the sun and moon, but t ...